Bring in support for Ingenic XBurst JZ4780 and
X1000 systems on chips. Imgtec CI20 and Ingenic CANNA boards supported. Submitted by: Alexander Kabaev <kan@FreeBSD.org> Reviewed by: Ruslan Bukin <br@FreeBSD.org> Sponsored by: DARPA, AFRL
This commit is contained in:
parent
9caeb4305d
commit
9a8f61fb5b
Notes:
svn2git
2020-12-20 02:59:44 +00:00
svn path=/head/; revision=308857
30
bin/dd/dd.c
30
bin/dd/dd.c
@ -48,13 +48,10 @@ __FBSDID("$FreeBSD$");
|
|||||||
#include <sys/param.h>
|
#include <sys/param.h>
|
||||||
#include <sys/stat.h>
|
#include <sys/stat.h>
|
||||||
#include <sys/conf.h>
|
#include <sys/conf.h>
|
||||||
#include <sys/capsicum.h>
|
|
||||||
#include <sys/disklabel.h>
|
#include <sys/disklabel.h>
|
||||||
#include <sys/filio.h>
|
#include <sys/filio.h>
|
||||||
#include <sys/mtio.h>
|
|
||||||
|
|
||||||
#include <assert.h>
|
#include <assert.h>
|
||||||
#include <capsicum_helpers.h>
|
|
||||||
#include <ctype.h>
|
#include <ctype.h>
|
||||||
#include <err.h>
|
#include <err.h>
|
||||||
#include <errno.h>
|
#include <errno.h>
|
||||||
@ -95,10 +92,6 @@ main(int argc __unused, char *argv[])
|
|||||||
jcl(argv);
|
jcl(argv);
|
||||||
setup();
|
setup();
|
||||||
|
|
||||||
caph_cache_catpages();
|
|
||||||
if (cap_enter() == -1 && errno != ENOSYS)
|
|
||||||
err(1, "unable to enter capability mode");
|
|
||||||
|
|
||||||
(void)signal(SIGINFO, siginfo_handler);
|
(void)signal(SIGINFO, siginfo_handler);
|
||||||
(void)signal(SIGINT, terminate);
|
(void)signal(SIGINT, terminate);
|
||||||
|
|
||||||
@ -132,8 +125,6 @@ static void
|
|||||||
setup(void)
|
setup(void)
|
||||||
{
|
{
|
||||||
u_int cnt;
|
u_int cnt;
|
||||||
cap_rights_t rights;
|
|
||||||
unsigned long cmds[] = { FIODTYPE, MTIOCTOP };
|
|
||||||
|
|
||||||
if (in.name == NULL) {
|
if (in.name == NULL) {
|
||||||
in.name = "stdin";
|
in.name = "stdin";
|
||||||
@ -142,20 +133,13 @@ setup(void)
|
|||||||
in.fd = open(in.name, O_RDONLY, 0);
|
in.fd = open(in.name, O_RDONLY, 0);
|
||||||
if (in.fd == -1)
|
if (in.fd == -1)
|
||||||
err(1, "%s", in.name);
|
err(1, "%s", in.name);
|
||||||
if (caph_limit_stdin() == -1)
|
|
||||||
err(1, "unable to limit capability rights");
|
|
||||||
}
|
}
|
||||||
|
|
||||||
getfdtype(&in);
|
getfdtype(&in);
|
||||||
|
|
||||||
cap_rights_init(&rights, CAP_READ, CAP_SEEK);
|
|
||||||
if (cap_rights_limit(in.fd, &rights) == -1 && errno != ENOSYS)
|
|
||||||
err(1, "unable to limit capability rights");
|
|
||||||
|
|
||||||
if (files_cnt > 1 && !(in.flags & ISTAPE))
|
if (files_cnt > 1 && !(in.flags & ISTAPE))
|
||||||
errx(1, "files is not supported for non-tape devices");
|
errx(1, "files is not supported for non-tape devices");
|
||||||
|
|
||||||
cap_rights_set(&rights, CAP_WRITE, CAP_FTRUNCATE, CAP_IOCTL);
|
|
||||||
if (out.name == NULL) {
|
if (out.name == NULL) {
|
||||||
/* No way to check for read access here. */
|
/* No way to check for read access here. */
|
||||||
out.fd = STDOUT_FILENO;
|
out.fd = STDOUT_FILENO;
|
||||||
@ -172,27 +156,13 @@ setup(void)
|
|||||||
if (out.fd == -1) {
|
if (out.fd == -1) {
|
||||||
out.fd = open(out.name, O_WRONLY | OFLAGS, DEFFILEMODE);
|
out.fd = open(out.name, O_WRONLY | OFLAGS, DEFFILEMODE);
|
||||||
out.flags |= NOREAD;
|
out.flags |= NOREAD;
|
||||||
cap_rights_clear(&rights, CAP_READ);
|
|
||||||
}
|
}
|
||||||
if (out.fd == -1)
|
if (out.fd == -1)
|
||||||
err(1, "%s", out.name);
|
err(1, "%s", out.name);
|
||||||
if (caph_limit_stdout() == -1)
|
|
||||||
err(1, "unable to limit capability rights");
|
|
||||||
}
|
}
|
||||||
|
|
||||||
getfdtype(&out);
|
getfdtype(&out);
|
||||||
|
|
||||||
if (cap_rights_limit(out.fd, &rights) == -1 && errno != ENOSYS)
|
|
||||||
err(1, "unable to limit capability rights");
|
|
||||||
if (cap_ioctls_limit(out.fd, cmds, nitems(cmds)) == -1 &&
|
|
||||||
errno != ENOSYS)
|
|
||||||
err(1, "unable to limit capability rights");
|
|
||||||
|
|
||||||
if (in.fd != STDERR_FILENO && out.fd != STDERR_FILENO) {
|
|
||||||
if (caph_limit_stderr() == -1)
|
|
||||||
err(1, "unable to limit capability rights");
|
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Allocate space for the input and output buffers. If not doing
|
* Allocate space for the input and output buffers. If not doing
|
||||||
* record oriented I/O, only need a single buffer.
|
* record oriented I/O, only need a single buffer.
|
||||||
|
29
sys/mips/conf/CANNA
Normal file
29
sys/mips/conf/CANNA
Normal file
@ -0,0 +1,29 @@
|
|||||||
|
# CANNA -- Kernel config for Ingenic CANNA board
|
||||||
|
#
|
||||||
|
# $FreeBSD$
|
||||||
|
|
||||||
|
include "X1000"
|
||||||
|
ident CANNA
|
||||||
|
|
||||||
|
options FDT
|
||||||
|
options FDT_DTB_STATIC
|
||||||
|
makeoptions FDT_DTS_FILE=ingenic/canna.dts
|
||||||
|
|
||||||
|
#options KTR
|
||||||
|
#options KTR_CPUMASK=0x3
|
||||||
|
#options KTR_MASK=(KTR_GEN)
|
||||||
|
#options KTR_COMPILE=(KTR_GEN)
|
||||||
|
#options KTR_VERBOSE
|
||||||
|
|
||||||
|
# Uncomment for NFS root
|
||||||
|
#options BOOTP
|
||||||
|
#options BOOTP_NFSROOT
|
||||||
|
#options BOOTP_NFSV3
|
||||||
|
#options BOOTP_WIRED_TO=dme0
|
||||||
|
#options BOOTP_COMPAT
|
||||||
|
options ROOTDEVNAME=\"ufs:mmcsd0s3\"
|
||||||
|
|
||||||
|
makeoptions TRAMPLOADADDR=0x88000000
|
||||||
|
|
||||||
|
#options VERBOSE_SYSINIT
|
||||||
|
options PRINTF_BUFR_SIZE=256
|
31
sys/mips/conf/CI20
Normal file
31
sys/mips/conf/CI20
Normal file
@ -0,0 +1,31 @@
|
|||||||
|
# CI20 -- Kernel config for Creator CI20 board
|
||||||
|
#
|
||||||
|
# $FreeBSD$
|
||||||
|
|
||||||
|
include "JZ4780"
|
||||||
|
ident CI20
|
||||||
|
|
||||||
|
options FDT
|
||||||
|
options FDT_DTB_STATIC
|
||||||
|
makeoptions FDT_DTS_FILE=ingenic/ci20.dts
|
||||||
|
|
||||||
|
#options KTR
|
||||||
|
#options KTR_CPUMASK=0x3
|
||||||
|
#options KTR_MASK=(KTR_GEN)
|
||||||
|
#options KTR_COMPILE=(KTR_GEN)
|
||||||
|
#options KTR_VERBOSE
|
||||||
|
|
||||||
|
# Uncomment for NFS root
|
||||||
|
#options BOOTP
|
||||||
|
#options BOOTP_NFSROOT
|
||||||
|
#options BOOTP_NFSV3
|
||||||
|
#options BOOTP_WIRED_TO=dme0
|
||||||
|
#options BOOTP_COMPAT
|
||||||
|
|
||||||
|
options ROOTDEVNAME=\"ufs:mmcsd0\"
|
||||||
|
|
||||||
|
makeoptions TRAMPLOADADDR=0x88000000
|
||||||
|
|
||||||
|
#options VERBOSE_SYSINIT
|
||||||
|
device dme
|
||||||
|
options PRINTF_BUFR_SIZE=256
|
92
sys/mips/conf/JZ4780
Normal file
92
sys/mips/conf/JZ4780
Normal file
@ -0,0 +1,92 @@
|
|||||||
|
# JZ4780 -- Kernel config for Ingenic JZ47XX boards
|
||||||
|
#
|
||||||
|
# $FreeBSD$
|
||||||
|
|
||||||
|
ident JZ4780
|
||||||
|
machine mips mipsel
|
||||||
|
cpu CPU_XBURST
|
||||||
|
cpu CPU_MIPS4KC
|
||||||
|
|
||||||
|
makeoptions KERNLOADADDR=0x80020000
|
||||||
|
makeoptions ARCH_FLAGS="-EL -march=mips32r2"
|
||||||
|
|
||||||
|
# Don't build any modules yet.
|
||||||
|
makeoptions MODULES_OVERRIDE=""
|
||||||
|
|
||||||
|
files "../ingenic/files.jz4780"
|
||||||
|
hints "JZ4780.hints" #Default places to look for devices.
|
||||||
|
|
||||||
|
makeoptions DEBUG=-g #Build kernel with gdb(1) debug symbols
|
||||||
|
|
||||||
|
options INTRNG # Borrow interrupt code from ARM
|
||||||
|
options MIPS_NIRQ=264 # 8 cpuintc + 64 intc + 6 * 23 gpio
|
||||||
|
|
||||||
|
options DDB
|
||||||
|
options KDB
|
||||||
|
options BREAK_TO_DEBUGGER
|
||||||
|
|
||||||
|
options COMPAT_FREEBSD10
|
||||||
|
|
||||||
|
options SCHED_4BSD #4BSD scheduler
|
||||||
|
options INET #InterNETworking
|
||||||
|
options NFSCL #Network Filesystem Client
|
||||||
|
options NFS_ROOT #NFS usable as /, requires NFSCL
|
||||||
|
options NFSLOCKD #Network Lock Manager
|
||||||
|
options PSEUDOFS #Pseudo-filesystem framework
|
||||||
|
options _KPOSIX_PRIORITY_SCHEDULING #Posix P1003_1B real-time extensions
|
||||||
|
|
||||||
|
options FFS #Berkeley Fast Filesystem
|
||||||
|
options SOFTUPDATES #Enable FFS soft updates support
|
||||||
|
options UFS_ACL #Support for access control lists
|
||||||
|
options UFS_DIRHASH #Improve performance on big directories
|
||||||
|
#options ROOTDEVNAME=\"ufs:ada0\"
|
||||||
|
|
||||||
|
options GEOM_LABEL # Provides labelization
|
||||||
|
options GEOM_PART_GPT # GUID Partition Tables.
|
||||||
|
#options GEOM_RAID # Soft RAID functionality.
|
||||||
|
|
||||||
|
# Debugging for use in -current
|
||||||
|
#options DEADLKRES #Enable the deadlock resolver
|
||||||
|
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
|
||||||
|
|
||||||
|
# Make an SMP-capable kernel by default
|
||||||
|
# options SMP # Symmetric MultiProcessor Kernel
|
||||||
|
|
||||||
|
device loop
|
||||||
|
device ether
|
||||||
|
#device le
|
||||||
|
device miibus
|
||||||
|
device bpf
|
||||||
|
device md
|
||||||
|
device uart
|
||||||
|
device random
|
||||||
|
|
||||||
|
device fdt_pinctrl
|
||||||
|
|
||||||
|
device clk
|
||||||
|
device regulator
|
||||||
|
device ext_resources
|
||||||
|
|
||||||
|
device gpio
|
||||||
|
|
||||||
|
device scbus
|
||||||
|
device da
|
||||||
|
|
||||||
|
device mmc
|
||||||
|
device mmcsd
|
||||||
|
|
||||||
|
# USB support
|
||||||
|
options USB_DEBUG # enable debug msgs
|
||||||
|
options USB_HOST_ALIGN=128 # L2 cache line size
|
||||||
|
device ohci # OHCI PCI->USB interface
|
||||||
|
device ehci # EHCI PCI->USB interface (USB 2.0)
|
||||||
|
device dwcotg # DesignWare HS OTG controller
|
||||||
|
device usb # USB Bus (required)
|
||||||
|
#device udbp # USB Double Bulk Pipe devices
|
||||||
|
device uhid # "Human Interface Devices"
|
||||||
|
#device ulpt # Printer
|
||||||
|
device umass # Disks/Mass storage - Requires scbus and da
|
||||||
|
device ums # Mouse
|
2
sys/mips/conf/JZ4780.hints
Normal file
2
sys/mips/conf/JZ4780.hints
Normal file
@ -0,0 +1,2 @@
|
|||||||
|
# $FreeBSD$
|
||||||
|
# device.hints
|
89
sys/mips/conf/X1000
Normal file
89
sys/mips/conf/X1000
Normal file
@ -0,0 +1,89 @@
|
|||||||
|
# X1000 -- Kernel config for Ingenic X1000 boards
|
||||||
|
#
|
||||||
|
# $FreeBSD$
|
||||||
|
|
||||||
|
ident X1000
|
||||||
|
machine mips mipsel
|
||||||
|
cpu CPU_XBURST
|
||||||
|
cpu CPU_MIPS4KC
|
||||||
|
|
||||||
|
makeoptions KERNLOADADDR=0x80020000
|
||||||
|
makeoptions ARCH_FLAGS="-EL -march=mips32r2"
|
||||||
|
|
||||||
|
# Don't build any modules yet.
|
||||||
|
makeoptions MODULES_OVERRIDE=""
|
||||||
|
|
||||||
|
files "../ingenic/files.x1000"
|
||||||
|
hints "X1000.hints" #Default places to look for devices.
|
||||||
|
|
||||||
|
makeoptions DEBUG=-g #Build kernel with gdb(1) debug symbols
|
||||||
|
|
||||||
|
options INTRNG # Borrow interrupt code from ARM
|
||||||
|
options MIPS_NIRQ=264 # 8 cpuintc + 64 intc + 6 * 23 gpio
|
||||||
|
|
||||||
|
options DDB
|
||||||
|
options KDB
|
||||||
|
options BREAK_TO_DEBUGGER
|
||||||
|
|
||||||
|
options COMPAT_FREEBSD10
|
||||||
|
|
||||||
|
options SCHED_4BSD #4BSD scheduler
|
||||||
|
options INET #InterNETworking
|
||||||
|
options NFSCL #Network Filesystem Client
|
||||||
|
options NFS_ROOT #NFS usable as /, requires NFSCL
|
||||||
|
options NFSLOCKD #Network Lock Manager
|
||||||
|
options PSEUDOFS #Pseudo-filesystem framework
|
||||||
|
options _KPOSIX_PRIORITY_SCHEDULING #Posix P1003_1B real-time extensions
|
||||||
|
|
||||||
|
options FFS #Berkeley Fast Filesystem
|
||||||
|
options SOFTUPDATES #Enable FFS soft updates support
|
||||||
|
options UFS_ACL #Support for access control lists
|
||||||
|
options UFS_DIRHASH #Improve performance on big directories
|
||||||
|
#options ROOTDEVNAME=\"ufs:ada0\"
|
||||||
|
|
||||||
|
options GEOM_LABEL # Provides labelization
|
||||||
|
options GEOM_PART_GPT # GUID Partition Tables.
|
||||||
|
#options GEOM_RAID # Soft RAID functionality.
|
||||||
|
|
||||||
|
# Debugging for use in -current
|
||||||
|
#options DEADLKRES #Enable the deadlock resolver
|
||||||
|
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
|
||||||
|
|
||||||
|
device loop
|
||||||
|
device ether
|
||||||
|
#device le
|
||||||
|
device miibus
|
||||||
|
device bpf
|
||||||
|
device md
|
||||||
|
device uart
|
||||||
|
device random
|
||||||
|
|
||||||
|
device fdt_pinctrl
|
||||||
|
|
||||||
|
device clk
|
||||||
|
device regulator
|
||||||
|
device ext_resources
|
||||||
|
|
||||||
|
device gpio
|
||||||
|
|
||||||
|
device scbus
|
||||||
|
device da
|
||||||
|
|
||||||
|
device mmc
|
||||||
|
device mmcsd
|
||||||
|
|
||||||
|
# USB support
|
||||||
|
#options USB_DEBUG # enable debug msgs
|
||||||
|
#options USB_HOST_ALIGN=128 # L2 cache line size
|
||||||
|
#device ohci # OHCI PCI->USB interface
|
||||||
|
#device ehci # EHCI PCI->USB interface (USB 2.0)
|
||||||
|
#device dwcotg # DesignWare HS OTG controller
|
||||||
|
#device usb # USB Bus (required)
|
||||||
|
#device udbp # USB Double Bulk Pipe devices
|
||||||
|
#device uhid # "Human Interface Devices"
|
||||||
|
#device ulpt # Printer
|
||||||
|
#device umass # Disks/Mass storage - Requires scbus and da
|
||||||
|
#device ums # Mouse
|
2
sys/mips/conf/X1000.hints
Normal file
2
sys/mips/conf/X1000.hints
Normal file
@ -0,0 +1,2 @@
|
|||||||
|
# $FreeBSD$
|
||||||
|
# device.hints
|
26
sys/mips/ingenic/files.jz4780
Normal file
26
sys/mips/ingenic/files.jz4780
Normal file
@ -0,0 +1,26 @@
|
|||||||
|
# $FreeBSD$
|
||||||
|
|
||||||
|
mips/ingenic/jz4780_dwc_fdt.c optional dwcotg
|
||||||
|
mips/ingenic/jz4780_ehci.c optional ehci
|
||||||
|
mips/ingenic/jz4780_mmc.c optional mmc
|
||||||
|
mips/ingenic/jz4780_ohci.c optional ohci
|
||||||
|
mips/ingenic/jz4780_uart.c optional uart
|
||||||
|
|
||||||
|
mips/ingenic/jz4780_clock.c standard
|
||||||
|
mips/ingenic/jz4780_clk_gen.c standard
|
||||||
|
mips/ingenic/jz4780_clk_otg.c standard
|
||||||
|
mips/ingenic/jz4780_clk_pll.c standard
|
||||||
|
mips/ingenic/jz4780_efuse.c standard
|
||||||
|
mips/ingenic/jz4780_intr.c standard
|
||||||
|
mips/ingenic/jz4780_gpio.c standard
|
||||||
|
mips/ingenic/jz4780_machdep.c standard
|
||||||
|
mips/ingenic/jz4780_nemc.c standard
|
||||||
|
mips/ingenic/jz4780_pinctrl.c standard
|
||||||
|
mips/ingenic/jz4780_timer.c standard
|
||||||
|
|
||||||
|
# SMP
|
||||||
|
mips/ingenic/jz4780_mp.c optional smp
|
||||||
|
mips/ingenic/jz4780_mpboot.S optional smp
|
||||||
|
|
||||||
|
# Custom interface between pinctrl and gpio
|
||||||
|
mips/ingenic/jz4780_gpio_if.m standard
|
17
sys/mips/ingenic/files.x1000
Normal file
17
sys/mips/ingenic/files.x1000
Normal file
@ -0,0 +1,17 @@
|
|||||||
|
# $FreeBSD$
|
||||||
|
|
||||||
|
mips/ingenic/jz4780_mmc.c optional mmc
|
||||||
|
mips/ingenic/jz4780_uart.c optional uart
|
||||||
|
|
||||||
|
mips/ingenic/jz4780_clock.c standard
|
||||||
|
mips/ingenic/jz4780_clk_gen.c standard
|
||||||
|
mips/ingenic/jz4780_clk_otg.c standard
|
||||||
|
mips/ingenic/jz4780_clk_pll.c standard
|
||||||
|
mips/ingenic/jz4780_intr.c standard
|
||||||
|
mips/ingenic/jz4780_gpio.c standard
|
||||||
|
mips/ingenic/jz4780_machdep.c standard
|
||||||
|
mips/ingenic/jz4780_pinctrl.c standard
|
||||||
|
mips/ingenic/jz4780_timer.c standard
|
||||||
|
|
||||||
|
# Custom interface between pinctrl and gpio
|
||||||
|
mips/ingenic/jz4780_gpio_if.m standard
|
93
sys/mips/ingenic/jz4780_clk.h
Normal file
93
sys/mips/ingenic/jz4780_clk.h
Normal file
@ -0,0 +1,93 @@
|
|||||||
|
/*-
|
||||||
|
* Copyright 2015 Alexander Kabaev <kan@FreeBSD.org>
|
||||||
|
* All rights reserved.
|
||||||
|
*
|
||||||
|
* Redistribution and use in source and binary forms, with or without
|
||||||
|
* modification, are permitted provided that the following conditions
|
||||||
|
* are met:
|
||||||
|
* 1. Redistributions of source code must retain the above copyright
|
||||||
|
* notice, this list of conditions and the following disclaimer.
|
||||||
|
* 2. Redistributions in binary form must reproduce the above copyright
|
||||||
|
* notice, this list of conditions and the following disclaimer in the
|
||||||
|
* documentation and/or other materials provided with the distribution.
|
||||||
|
*
|
||||||
|
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
|
||||||
|
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||||
|
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
||||||
|
* ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
|
||||||
|
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
|
||||||
|
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
|
||||||
|
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
|
||||||
|
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
|
||||||
|
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
|
||||||
|
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
|
||||||
|
* SUCH DAMAGE.
|
||||||
|
*
|
||||||
|
* $FreeBSD$
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef _MIPS_INGENIC_JZ4780_CLK_H
|
||||||
|
#define _MIPS_INGENIC_JZ4780_CLK_H
|
||||||
|
|
||||||
|
#include <dev/extres/clk/clk.h>
|
||||||
|
#include <dev/extres/clk/clk_gate.h>
|
||||||
|
|
||||||
|
/* Convenience bitfiled manipulation macros */
|
||||||
|
#define REG_MSK(field) (((1u << field ## _WIDTH) - 1) << field ##_SHIFT)
|
||||||
|
#define REG_VAL(field, val) ((val) << field ##_SHIFT)
|
||||||
|
#define REG_CLR(reg, field) ((reg) & ~REG_MSK(field))
|
||||||
|
#define REG_GET(reg, field) (((reg) & REG_MSK(field)) >> field ##_SHIFT)
|
||||||
|
#define REG_SET(reg, field, val) (REG_CLR(reg, field) | REG_VAL(field, val))
|
||||||
|
|
||||||
|
/* Common clock macros */
|
||||||
|
#define CLK_LOCK(_sc) mtx_lock((_sc)->clk_mtx)
|
||||||
|
#define CLK_UNLOCK(_sc) mtx_unlock((_sc)->clk_mtx)
|
||||||
|
|
||||||
|
#define CLK_WR_4(_sc, off, val) bus_write_4((_sc)->clk_res, (off), (val))
|
||||||
|
#define CLK_RD_4(_sc, off) bus_read_4((_sc)->clk_res, (off))
|
||||||
|
|
||||||
|
struct jz4780_clk_mux_descr {
|
||||||
|
uint16_t mux_reg;
|
||||||
|
uint16_t mux_shift: 5;
|
||||||
|
uint16_t mux_bits: 5;
|
||||||
|
uint16_t mux_map: 4; /* Map into mux space */
|
||||||
|
};
|
||||||
|
|
||||||
|
struct jz4780_clk_div_descr {
|
||||||
|
uint16_t div_reg;
|
||||||
|
uint16_t div_shift: 5;
|
||||||
|
uint16_t div_bits: 5;
|
||||||
|
uint16_t div_lg: 5;
|
||||||
|
int div_ce_bit: 6; /* -1, if CE bit is not present */
|
||||||
|
int div_st_bit: 6; /* Can be negative */
|
||||||
|
int div_busy_bit: 6; /* Can be negative */
|
||||||
|
};
|
||||||
|
|
||||||
|
struct jz4780_clk_descr {
|
||||||
|
uint16_t clk_id: 6;
|
||||||
|
uint16_t clk_type: 3;
|
||||||
|
int clk_gate_bit: 7; /* Can be negative */
|
||||||
|
struct jz4780_clk_mux_descr clk_mux;
|
||||||
|
struct jz4780_clk_div_descr clk_div;
|
||||||
|
const char *clk_name;
|
||||||
|
const char *clk_pnames[4];
|
||||||
|
};
|
||||||
|
|
||||||
|
/* clk_type bits */
|
||||||
|
#define CLK_MASK_GATE 0x01
|
||||||
|
#define CLK_MASK_DIV 0x02
|
||||||
|
#define CLK_MASK_MUX 0x04
|
||||||
|
|
||||||
|
extern int jz4780_clk_gen_register(struct clkdom *clkdom,
|
||||||
|
const struct jz4780_clk_descr *descr, struct mtx *dev_mtx,
|
||||||
|
struct resource *mem_res);
|
||||||
|
|
||||||
|
extern int jz4780_clk_pll_register(struct clkdom *clkdom,
|
||||||
|
struct clknode_init_def *clkdef, struct mtx *dev_mtx,
|
||||||
|
struct resource *mem_res, uint32_t mem_reg);
|
||||||
|
|
||||||
|
extern int jz4780_clk_otg_register(struct clkdom *clkdom,
|
||||||
|
struct clknode_init_def *clkdef, struct mtx *dev_mtx,
|
||||||
|
struct resource *mem_res);
|
||||||
|
|
||||||
|
#endif /* _MIPS_INGENIC_JZ4780_CLK_PLL_H */
|
317
sys/mips/ingenic/jz4780_clk_gen.c
Normal file
317
sys/mips/ingenic/jz4780_clk_gen.c
Normal file
@ -0,0 +1,317 @@
|
|||||||
|
/*-
|
||||||
|
* Copyright 2015 Alexander Kabaev <kan@FreeBSD.org>
|
||||||
|
* All rights reserved.
|
||||||
|
*
|
||||||
|
* Redistribution and use in source and binary forms, with or without
|
||||||
|
* modification, are permitted provided that the following conditions
|
||||||
|
* are met:
|
||||||
|
* 1. Redistributions of source code must retain the above copyright
|
||||||
|
* notice, this list of conditions and the following disclaimer.
|
||||||
|
* 2. Redistributions in binary form must reproduce the above copyright
|
||||||
|
* notice, this list of conditions and the following disclaimer in the
|
||||||
|
* documentation and/or other materials provided with the distribution.
|
||||||
|
*
|
||||||
|
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
|
||||||
|
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||||
|
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
||||||
|
* ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
|
||||||
|
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
|
||||||
|
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
|
||||||
|
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
|
||||||
|
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
|
||||||
|
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
|
||||||
|
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
|
||||||
|
* SUCH DAMAGE.
|
||||||
|
*/
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Ingenic JZ4780 generic CGU clock driver.
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include <sys/cdefs.h>
|
||||||
|
__FBSDID("$FreeBSD$");
|
||||||
|
|
||||||
|
#include <sys/param.h>
|
||||||
|
#include <sys/systm.h>
|
||||||
|
#include <sys/conf.h>
|
||||||
|
#include <sys/bus.h>
|
||||||
|
#include <sys/lock.h>
|
||||||
|
#include <sys/mutex.h>
|
||||||
|
#include <sys/resource.h>
|
||||||
|
|
||||||
|
#include <machine/bus.h>
|
||||||
|
|
||||||
|
#include <mips/ingenic/jz4780_clk.h>
|
||||||
|
#include <mips/ingenic/jz4780_regs.h>
|
||||||
|
|
||||||
|
/* JZ4780 generic mux and div clocks implementation */
|
||||||
|
static int jz4780_clk_gen_init(struct clknode *clk, device_t dev);
|
||||||
|
static int jz4780_clk_gen_recalc_freq(struct clknode *clk, uint64_t *freq);
|
||||||
|
static int jz4780_clk_gen_set_freq(struct clknode *clk, uint64_t fin,
|
||||||
|
uint64_t *fout, int flags, int *stop);
|
||||||
|
static int jz4780_clk_gen_set_gate(struct clknode *clk, bool enable);
|
||||||
|
static int jz4780_clk_gen_set_mux(struct clknode *clk, int src);
|
||||||
|
|
||||||
|
struct jz4780_clk_gen_sc {
|
||||||
|
struct mtx *clk_mtx;
|
||||||
|
struct resource *clk_res;
|
||||||
|
int clk_reg;
|
||||||
|
const struct jz4780_clk_descr *clk_descr;
|
||||||
|
};
|
||||||
|
|
||||||
|
/*
|
||||||
|
* JZ4780 clock PLL clock methods
|
||||||
|
*/
|
||||||
|
static clknode_method_t jz4780_clk_gen_methods[] = {
|
||||||
|
CLKNODEMETHOD(clknode_init, jz4780_clk_gen_init),
|
||||||
|
CLKNODEMETHOD(clknode_set_gate, jz4780_clk_gen_set_gate),
|
||||||
|
CLKNODEMETHOD(clknode_recalc_freq, jz4780_clk_gen_recalc_freq),
|
||||||
|
CLKNODEMETHOD(clknode_set_freq, jz4780_clk_gen_set_freq),
|
||||||
|
CLKNODEMETHOD(clknode_set_mux, jz4780_clk_gen_set_mux),
|
||||||
|
|
||||||
|
CLKNODEMETHOD_END
|
||||||
|
};
|
||||||
|
DEFINE_CLASS_1(jz4780_clk_pll, jz4780_clk_gen_class, jz4780_clk_gen_methods,
|
||||||
|
sizeof(struct jz4780_clk_gen_sc), clknode_class);
|
||||||
|
|
||||||
|
static inline unsigned
|
||||||
|
mux_to_reg(unsigned src, unsigned map)
|
||||||
|
{
|
||||||
|
unsigned ret, bit;
|
||||||
|
|
||||||
|
bit = (1u << 3);
|
||||||
|
for (ret = 0; bit; ret++, bit >>= 1) {
|
||||||
|
if (map & bit) {
|
||||||
|
if (src-- == 0)
|
||||||
|
return (ret);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
panic("mux_to_reg");
|
||||||
|
}
|
||||||
|
|
||||||
|
static inline unsigned
|
||||||
|
reg_to_mux(unsigned reg, unsigned map)
|
||||||
|
{
|
||||||
|
unsigned ret, bit;
|
||||||
|
|
||||||
|
bit = (1u << 3);
|
||||||
|
for (ret = 0; reg; reg--, bit >>= 1)
|
||||||
|
if (map & bit)
|
||||||
|
ret++;
|
||||||
|
return (ret);
|
||||||
|
}
|
||||||
|
|
||||||
|
static int
|
||||||
|
jz4780_clk_gen_init(struct clknode *clk, device_t dev)
|
||||||
|
{
|
||||||
|
struct jz4780_clk_gen_sc *sc;
|
||||||
|
uint32_t reg, msk, parent_idx;
|
||||||
|
|
||||||
|
sc = clknode_get_softc(clk);
|
||||||
|
CLK_LOCK(sc);
|
||||||
|
/* Figure our parent out */
|
||||||
|
if (sc->clk_descr->clk_type & CLK_MASK_MUX) {
|
||||||
|
msk = (1u << sc->clk_descr->clk_mux.mux_bits) - 1;
|
||||||
|
reg = CLK_RD_4(sc, sc->clk_descr->clk_mux.mux_reg);
|
||||||
|
reg = (reg >> sc->clk_descr->clk_mux.mux_shift) & msk;
|
||||||
|
parent_idx = reg_to_mux(reg, sc->clk_descr->clk_mux.mux_map);
|
||||||
|
} else
|
||||||
|
parent_idx = 0;
|
||||||
|
CLK_UNLOCK(sc);
|
||||||
|
|
||||||
|
clknode_init_parent_idx(clk, parent_idx);
|
||||||
|
return (0);
|
||||||
|
}
|
||||||
|
|
||||||
|
static int
|
||||||
|
jz4780_clk_gen_recalc_freq(struct clknode *clk, uint64_t *freq)
|
||||||
|
{
|
||||||
|
struct jz4780_clk_gen_sc *sc;
|
||||||
|
uint32_t reg;
|
||||||
|
|
||||||
|
sc = clknode_get_softc(clk);
|
||||||
|
|
||||||
|
/* Calculate divisor frequency */
|
||||||
|
if (sc->clk_descr->clk_type & CLK_MASK_DIV) {
|
||||||
|
uint32_t msk;
|
||||||
|
|
||||||
|
msk = (1u << sc->clk_descr->clk_div.div_bits) - 1;
|
||||||
|
reg = CLK_RD_4(sc, sc->clk_descr->clk_div.div_reg);
|
||||||
|
reg = (reg >> sc->clk_descr->clk_div.div_shift) & msk;
|
||||||
|
reg = (reg + 1) << sc->clk_descr->clk_div.div_lg;
|
||||||
|
*freq /= reg;
|
||||||
|
}
|
||||||
|
return (0);
|
||||||
|
}
|
||||||
|
|
||||||
|
#define DIV_TIMEOUT 100
|
||||||
|
|
||||||
|
static int
|
||||||
|
jz4780_clk_gen_set_freq(struct clknode *clk, uint64_t fin,
|
||||||
|
uint64_t *fout, int flags, int *stop)
|
||||||
|
{
|
||||||
|
struct jz4780_clk_gen_sc *sc;
|
||||||
|
uint64_t _fout;
|
||||||
|
uint32_t divider, div_reg, div_msk, reg;
|
||||||
|
int rv;
|
||||||
|
|
||||||
|
sc = clknode_get_softc(clk);
|
||||||
|
|
||||||
|
divider = fin / *fout;
|
||||||
|
|
||||||
|
/* Adjust for divider multiplier */
|
||||||
|
div_reg = divider >> sc->clk_descr->clk_div.div_lg;
|
||||||
|
divider = div_reg << sc->clk_descr->clk_div.div_lg;
|
||||||
|
|
||||||
|
_fout = fin / divider;
|
||||||
|
|
||||||
|
/* Rounding */
|
||||||
|
if ((flags & CLK_SET_ROUND_UP) && (*fout < _fout))
|
||||||
|
div_reg--;
|
||||||
|
else if ((flags & CLK_SET_ROUND_DOWN) && (*fout > _fout))
|
||||||
|
div_reg++;
|
||||||
|
if (div_reg == 0)
|
||||||
|
div_reg = 1;
|
||||||
|
|
||||||
|
div_msk = (1u << sc->clk_descr->clk_div.div_bits) - 1;
|
||||||
|
|
||||||
|
*stop = 1;
|
||||||
|
if (div_reg > div_msk + 1) {
|
||||||
|
*stop = 0;
|
||||||
|
div_reg = div_msk;
|
||||||
|
}
|
||||||
|
|
||||||
|
divider = (div_reg << sc->clk_descr->clk_div.div_lg);
|
||||||
|
div_reg--;
|
||||||
|
|
||||||
|
if ((flags & CLK_SET_DRYRUN) != 0) {
|
||||||
|
if (*stop != 0 && *fout != fin / divider &&
|
||||||
|
(flags & (CLK_SET_ROUND_UP | CLK_SET_ROUND_DOWN)) == 0)
|
||||||
|
return (ERANGE);
|
||||||
|
*fout = fin / divider;
|
||||||
|
return (0);
|
||||||
|
}
|
||||||
|
|
||||||
|
CLK_LOCK(sc);
|
||||||
|
/* Apply the new divider value */
|
||||||
|
reg = CLK_RD_4(sc, sc->clk_descr->clk_div.div_reg);
|
||||||
|
reg &= ~(div_msk << sc->clk_descr->clk_div.div_shift);
|
||||||
|
reg |= (div_reg << sc->clk_descr->clk_div.div_shift);
|
||||||
|
/* Set the change enable bit, it present */
|
||||||
|
if (sc->clk_descr->clk_div.div_ce_bit >= 0)
|
||||||
|
reg |= (1u << sc->clk_descr->clk_div.div_ce_bit);
|
||||||
|
/* Clear stop bit, it present */
|
||||||
|
if (sc->clk_descr->clk_div.div_st_bit >= 0)
|
||||||
|
reg &= ~(1u << sc->clk_descr->clk_div.div_st_bit);
|
||||||
|
/* Initiate the change */
|
||||||
|
CLK_WR_4(sc, sc->clk_descr->clk_div.div_reg, reg);
|
||||||
|
|
||||||
|
/* Wait for busy bit to clear indicating the change is complete */
|
||||||
|
rv = 0;
|
||||||
|
if (sc->clk_descr->clk_div.div_busy_bit >= 0) {
|
||||||
|
int i;
|
||||||
|
|
||||||
|
for (i = 0; i < DIV_TIMEOUT; i++) {
|
||||||
|
reg = CLK_RD_4(sc, sc->clk_descr->clk_div.div_reg);
|
||||||
|
if (!(reg & (1u << sc->clk_descr->clk_div.div_busy_bit)))
|
||||||
|
break;
|
||||||
|
DELAY(1000);
|
||||||
|
}
|
||||||
|
if (i == DIV_TIMEOUT)
|
||||||
|
rv = ETIMEDOUT;
|
||||||
|
}
|
||||||
|
CLK_UNLOCK(sc);
|
||||||
|
|
||||||
|
*fout = fin / divider;
|
||||||
|
return (rv);
|
||||||
|
}
|
||||||
|
|
||||||
|
static int
|
||||||
|
jz4780_clk_gen_set_mux(struct clknode *clk, int src)
|
||||||
|
{
|
||||||
|
struct jz4780_clk_gen_sc *sc;
|
||||||
|
uint32_t reg, msk;
|
||||||
|
|
||||||
|
sc = clknode_get_softc(clk);
|
||||||
|
|
||||||
|
/* Only mux nodes are capable of being reparented */
|
||||||
|
if (!(sc->clk_descr->clk_type & CLK_MASK_MUX))
|
||||||
|
return (src ? EINVAL : 0);
|
||||||
|
|
||||||
|
msk = (1u << sc->clk_descr->clk_mux.mux_bits) - 1;
|
||||||
|
src = mux_to_reg(src & msk, sc->clk_descr->clk_mux.mux_map);
|
||||||
|
|
||||||
|
CLK_LOCK(sc);
|
||||||
|
reg = CLK_RD_4(sc, sc->clk_descr->clk_mux.mux_reg);
|
||||||
|
reg &= ~(msk << sc->clk_descr->clk_mux.mux_shift);
|
||||||
|
reg |= (src << sc->clk_descr->clk_mux.mux_shift);
|
||||||
|
CLK_WR_4(sc, sc->clk_descr->clk_mux.mux_reg, reg);
|
||||||
|
CLK_UNLOCK(sc);
|
||||||
|
|
||||||
|
return (0);
|
||||||
|
}
|
||||||
|
|
||||||
|
static int
|
||||||
|
jz4780_clk_gen_set_gate(struct clknode *clk, bool enable)
|
||||||
|
{
|
||||||
|
struct jz4780_clk_gen_sc *sc;
|
||||||
|
uint32_t off, reg, bit;
|
||||||
|
|
||||||
|
sc = clknode_get_softc(clk);
|
||||||
|
|
||||||
|
/* Check is clock can be gated */
|
||||||
|
if (sc->clk_descr->clk_gate_bit < 0)
|
||||||
|
return 0;
|
||||||
|
|
||||||
|
bit = sc->clk_descr->clk_gate_bit;
|
||||||
|
if (bit < 32) {
|
||||||
|
off = JZ_CLKGR0;
|
||||||
|
} else {
|
||||||
|
off = JZ_CLKGR1;
|
||||||
|
bit -= 32;
|
||||||
|
}
|
||||||
|
|
||||||
|
CLK_LOCK(sc);
|
||||||
|
reg = CLK_RD_4(sc, off);
|
||||||
|
if (enable)
|
||||||
|
reg &= ~(1u << bit);
|
||||||
|
else
|
||||||
|
reg |= (1u << bit);
|
||||||
|
CLK_WR_4(sc, off, reg);
|
||||||
|
CLK_UNLOCK(sc);
|
||||||
|
|
||||||
|
return (0);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
int jz4780_clk_gen_register(struct clkdom *clkdom,
|
||||||
|
const struct jz4780_clk_descr *descr, struct mtx *dev_mtx,
|
||||||
|
struct resource *mem_res)
|
||||||
|
{
|
||||||
|
struct clknode_init_def clkdef;
|
||||||
|
struct clknode *clk;
|
||||||
|
struct jz4780_clk_gen_sc *sc;
|
||||||
|
|
||||||
|
clkdef.id = descr->clk_id;
|
||||||
|
clkdef.name = __DECONST(char *, descr->clk_name);
|
||||||
|
/* Silly const games to work around API deficiency */
|
||||||
|
clkdef.parent_names = (const char **)(uintptr_t)&descr->clk_pnames[0];
|
||||||
|
clkdef.flags = CLK_NODE_STATIC_STRINGS;
|
||||||
|
if (descr->clk_type & CLK_MASK_MUX)
|
||||||
|
clkdef.parent_cnt = __bitcount16(descr->clk_mux.mux_map);
|
||||||
|
else
|
||||||
|
clkdef.parent_cnt = 1;
|
||||||
|
|
||||||
|
clk = clknode_create(clkdom, &jz4780_clk_gen_class, &clkdef);
|
||||||
|
if (clk == NULL)
|
||||||
|
return (1);
|
||||||
|
|
||||||
|
sc = clknode_get_softc(clk);
|
||||||
|
sc->clk_mtx = dev_mtx;
|
||||||
|
sc->clk_res = mem_res;
|
||||||
|
sc->clk_descr = descr;
|
||||||
|
clknode_register(clkdom, clk);
|
||||||
|
|
||||||
|
return (0);
|
||||||
|
}
|
167
sys/mips/ingenic/jz4780_clk_otg.c
Normal file
167
sys/mips/ingenic/jz4780_clk_otg.c
Normal file
@ -0,0 +1,167 @@
|
|||||||
|
/*-
|
||||||
|
* Copyright 2015 Alexander Kabaev <kan@FreeBSD.org>
|
||||||
|
* All rights reserved.
|
||||||
|
*
|
||||||
|
* Redistribution and use in source and binary forms, with or without
|
||||||
|
* modification, are permitted provided that the following conditions
|
||||||
|
* are met:
|
||||||
|
* 1. Redistributions of source code must retain the above copyright
|
||||||
|
* notice, this list of conditions and the following disclaimer.
|
||||||
|
* 2. Redistributions in binary form must reproduce the above copyright
|
||||||
|
* notice, this list of conditions and the following disclaimer in the
|
||||||
|
* documentation and/or other materials provided with the distribution.
|
||||||
|
*
|
||||||
|
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
|
||||||
|
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||||
|
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
||||||
|
* ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
|
||||||
|
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
|
||||||
|
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
|
||||||
|
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
|
||||||
|
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
|
||||||
|
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
|
||||||
|
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
|
||||||
|
* SUCH DAMAGE.
|
||||||
|
*/
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Ingenic JZ4780 OTG PHY clock driver.
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include <sys/cdefs.h>
|
||||||
|
__FBSDID("$FreeBSD$");
|
||||||
|
|
||||||
|
#include <sys/param.h>
|
||||||
|
#include <sys/systm.h>
|
||||||
|
#include <sys/conf.h>
|
||||||
|
#include <sys/bus.h>
|
||||||
|
#include <sys/lock.h>
|
||||||
|
#include <sys/mutex.h>
|
||||||
|
#include <sys/resource.h>
|
||||||
|
|
||||||
|
#include <machine/bus.h>
|
||||||
|
|
||||||
|
#include <mips/ingenic/jz4780_clk.h>
|
||||||
|
#include <mips/ingenic/jz4780_regs.h>
|
||||||
|
|
||||||
|
/* JZ4780 OTG PHY clock */
|
||||||
|
static int jz4780_clk_otg_init(struct clknode *clk, device_t dev);
|
||||||
|
static int jz4780_clk_otg_recalc_freq(struct clknode *clk, uint64_t *freq);
|
||||||
|
static int jz4780_clk_otg_set_freq(struct clknode *clk, uint64_t fin,
|
||||||
|
uint64_t *fout, int flags, int *stop);
|
||||||
|
|
||||||
|
struct jz4780_clk_otg_sc {
|
||||||
|
struct mtx *clk_mtx;
|
||||||
|
struct resource *clk_res;
|
||||||
|
};
|
||||||
|
|
||||||
|
/*
|
||||||
|
* JZ4780 OTG PHY clock methods
|
||||||
|
*/
|
||||||
|
static clknode_method_t jz4780_clk_otg_methods[] = {
|
||||||
|
CLKNODEMETHOD(clknode_init, jz4780_clk_otg_init),
|
||||||
|
CLKNODEMETHOD(clknode_recalc_freq, jz4780_clk_otg_recalc_freq),
|
||||||
|
CLKNODEMETHOD(clknode_set_freq, jz4780_clk_otg_set_freq),
|
||||||
|
|
||||||
|
CLKNODEMETHOD_END
|
||||||
|
};
|
||||||
|
DEFINE_CLASS_1(jz4780_clk_pll, jz4780_clk_otg_class, jz4780_clk_otg_methods,
|
||||||
|
sizeof(struct jz4780_clk_otg_sc), clknode_class);
|
||||||
|
|
||||||
|
static int
|
||||||
|
jz4780_clk_otg_init(struct clknode *clk, device_t dev)
|
||||||
|
{
|
||||||
|
struct jz4780_clk_otg_sc *sc;
|
||||||
|
uint32_t reg;
|
||||||
|
|
||||||
|
sc = clknode_get_softc(clk);
|
||||||
|
CLK_LOCK(sc);
|
||||||
|
/* Force the use fo the core clock */
|
||||||
|
reg = CLK_RD_4(sc, JZ_USBPCR1);
|
||||||
|
reg &= ~PCR_REFCLK_M;
|
||||||
|
reg |= PCR_REFCLK_CORE;
|
||||||
|
CLK_WR_4(sc, JZ_USBPCR1, reg);
|
||||||
|
CLK_UNLOCK(sc);
|
||||||
|
|
||||||
|
clknode_init_parent_idx(clk, 0);
|
||||||
|
return (0);
|
||||||
|
}
|
||||||
|
|
||||||
|
static const struct {
|
||||||
|
uint32_t div_val;
|
||||||
|
uint32_t freq;
|
||||||
|
} otg_div_table[] = {
|
||||||
|
{ PCR_CLK_12, 12000000 },
|
||||||
|
{ PCR_CLK_192, 19200000 },
|
||||||
|
{ PCR_CLK_24, 24000000 },
|
||||||
|
{ PCR_CLK_48, 48000000 }
|
||||||
|
};
|
||||||
|
|
||||||
|
static int
|
||||||
|
jz4780_clk_otg_recalc_freq(struct clknode *clk, uint64_t *freq)
|
||||||
|
{
|
||||||
|
struct jz4780_clk_otg_sc *sc;
|
||||||
|
uint32_t reg;
|
||||||
|
int i;
|
||||||
|
|
||||||
|
sc = clknode_get_softc(clk);
|
||||||
|
reg = CLK_RD_4(sc, JZ_USBPCR1);
|
||||||
|
reg &= PCR_CLK_M;
|
||||||
|
|
||||||
|
for (i = 0; i < nitems(otg_div_table); i++)
|
||||||
|
if (otg_div_table[i].div_val == reg)
|
||||||
|
*freq = otg_div_table[i].freq;
|
||||||
|
return (0);
|
||||||
|
}
|
||||||
|
|
||||||
|
static int
|
||||||
|
jz4780_clk_otg_set_freq(struct clknode *clk, uint64_t fin,
|
||||||
|
uint64_t *fout, int flags, int *stop)
|
||||||
|
{
|
||||||
|
struct jz4780_clk_otg_sc *sc;
|
||||||
|
uint32_t reg;
|
||||||
|
int i;
|
||||||
|
|
||||||
|
sc = clknode_get_softc(clk);
|
||||||
|
|
||||||
|
for (i = 0; i < nitems(otg_div_table) - 1; i++) {
|
||||||
|
if (*fout < (otg_div_table[i].freq + otg_div_table[i + 1].freq) / 2)
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
*fout = otg_div_table[i].freq;
|
||||||
|
|
||||||
|
*stop = 1;
|
||||||
|
if (flags & CLK_SET_DRYRUN)
|
||||||
|
return (0);
|
||||||
|
|
||||||
|
CLK_LOCK(sc);
|
||||||
|
reg = CLK_RD_4(sc, JZ_USBPCR1);
|
||||||
|
/* Set the calculated values */
|
||||||
|
reg &= ~PCR_CLK_M;
|
||||||
|
reg |= otg_div_table[i].div_val;
|
||||||
|
/* Initiate the change */
|
||||||
|
CLK_WR_4(sc, JZ_USBPCR1, reg);
|
||||||
|
CLK_UNLOCK(sc);
|
||||||
|
|
||||||
|
return (0);
|
||||||
|
}
|
||||||
|
|
||||||
|
int jz4780_clk_otg_register(struct clkdom *clkdom,
|
||||||
|
struct clknode_init_def *clkdef, struct mtx *dev_mtx,
|
||||||
|
struct resource *mem_res)
|
||||||
|
{
|
||||||
|
struct clknode *clk;
|
||||||
|
struct jz4780_clk_otg_sc *sc;
|
||||||
|
|
||||||
|
clk = clknode_create(clkdom, &jz4780_clk_otg_class, clkdef);
|
||||||
|
if (clk == NULL)
|
||||||
|
return (1);
|
||||||
|
|
||||||
|
sc = clknode_get_softc(clk);
|
||||||
|
sc->clk_mtx = dev_mtx;
|
||||||
|
sc->clk_res = mem_res;
|
||||||
|
clknode_register(clkdom, clk);
|
||||||
|
return (0);
|
||||||
|
}
|
234
sys/mips/ingenic/jz4780_clk_pll.c
Normal file
234
sys/mips/ingenic/jz4780_clk_pll.c
Normal file
@ -0,0 +1,234 @@
|
|||||||
|
/*-
|
||||||
|
* Copyright 2015 Alexander Kabaev <kan@FreeBSD.org>
|
||||||
|
* All rights reserved.
|
||||||
|
*
|
||||||
|
* Redistribution and use in source and binary forms, with or without
|
||||||
|
* modification, are permitted provided that the following conditions
|
||||||
|
* are met:
|
||||||
|
* 1. Redistributions of source code must retain the above copyright
|
||||||
|
* notice, this list of conditions and the following disclaimer.
|
||||||
|
* 2. Redistributions in binary form must reproduce the above copyright
|
||||||
|
* notice, this list of conditions and the following disclaimer in the
|
||||||
|
* documentation and/or other materials provided with the distribution.
|
||||||
|
*
|
||||||
|
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
|
||||||
|
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||||
|
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
||||||
|
* ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
|
||||||
|
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
|
||||||
|
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
|
||||||
|
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
|
||||||
|
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
|
||||||
|
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
|
||||||
|
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
|
||||||
|
* SUCH DAMAGE.
|
||||||
|
*/
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Ingenic JZ4780 CGU driver.
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include <sys/cdefs.h>
|
||||||
|
__FBSDID("$FreeBSD$");
|
||||||
|
|
||||||
|
#include <sys/param.h>
|
||||||
|
#include <sys/systm.h>
|
||||||
|
#include <sys/conf.h>
|
||||||
|
#include <sys/bus.h>
|
||||||
|
#include <sys/lock.h>
|
||||||
|
#include <sys/mutex.h>
|
||||||
|
#include <sys/resource.h>
|
||||||
|
|
||||||
|
#include <machine/bus.h>
|
||||||
|
|
||||||
|
#include <mips/ingenic/jz4780_clk.h>
|
||||||
|
|
||||||
|
/**********************************************************************
|
||||||
|
* JZ4780 PLL control register bit fields
|
||||||
|
**********************************************************************/
|
||||||
|
#define CGU_PLL_M_SHIFT 19
|
||||||
|
#define CGU_PLL_M_WIDTH 13
|
||||||
|
|
||||||
|
#define CGU_PLL_N_SHIFT 13
|
||||||
|
#define CGU_PLL_N_WIDTH 6
|
||||||
|
|
||||||
|
#define CGU_PLL_OD_SHIFT 9
|
||||||
|
#define CGU_PLL_OD_WIDTH 4
|
||||||
|
|
||||||
|
#define CGU_PLL_LOCK_SHIFT 6
|
||||||
|
#define CGU_PLL_LOCK_WIDTH 1
|
||||||
|
|
||||||
|
#define CGU_PLL_ON_SHIFT 4
|
||||||
|
#define CGU_PLL_ON_WIDTH 1
|
||||||
|
|
||||||
|
#define CGU_PLL_MODE_SHIFT 3
|
||||||
|
#define CGU_PLL_MODE_WIDTH 1
|
||||||
|
|
||||||
|
#define CGU_PLL_BP_SHIFT 1
|
||||||
|
#define CGU_PLL_BP_WIDTH 1
|
||||||
|
|
||||||
|
#define CGU_PLL_EN_SHIFT 0
|
||||||
|
#define CGU_PLL_EN_WIDTH 1
|
||||||
|
|
||||||
|
/* JZ4780 PLL clock */
|
||||||
|
static int jz4780_clk_pll_init(struct clknode *clk, device_t dev);
|
||||||
|
static int jz4780_clk_pll_recalc_freq(struct clknode *clk, uint64_t *freq);
|
||||||
|
static int jz4780_clk_pll_set_freq(struct clknode *clk, uint64_t fin,
|
||||||
|
uint64_t *fout, int flags, int *stop);
|
||||||
|
|
||||||
|
struct jz4780_clk_pll_sc {
|
||||||
|
struct mtx *clk_mtx;
|
||||||
|
struct resource *clk_res;
|
||||||
|
uint32_t clk_reg;
|
||||||
|
};
|
||||||
|
|
||||||
|
/*
|
||||||
|
* JZ4780 PLL clock methods
|
||||||
|
*/
|
||||||
|
static clknode_method_t jz4780_clk_pll_methods[] = {
|
||||||
|
CLKNODEMETHOD(clknode_init, jz4780_clk_pll_init),
|
||||||
|
CLKNODEMETHOD(clknode_recalc_freq, jz4780_clk_pll_recalc_freq),
|
||||||
|
CLKNODEMETHOD(clknode_set_freq, jz4780_clk_pll_set_freq),
|
||||||
|
|
||||||
|
CLKNODEMETHOD_END
|
||||||
|
};
|
||||||
|
DEFINE_CLASS_1(jz4780_clk_pll, jz4780_clk_pll_class, jz4780_clk_pll_methods,
|
||||||
|
sizeof(struct jz4780_clk_pll_sc), clknode_class);
|
||||||
|
|
||||||
|
static int
|
||||||
|
jz4780_clk_pll_init(struct clknode *clk, device_t dev)
|
||||||
|
{
|
||||||
|
struct jz4780_clk_pll_sc *sc;
|
||||||
|
uint32_t reg;
|
||||||
|
|
||||||
|
sc = clknode_get_softc(clk);
|
||||||
|
CLK_LOCK(sc);
|
||||||
|
reg = CLK_RD_4(sc, sc->clk_reg);
|
||||||
|
CLK_WR_4(sc, sc->clk_reg, reg);
|
||||||
|
CLK_UNLOCK(sc);
|
||||||
|
|
||||||
|
clknode_init_parent_idx(clk, 0);
|
||||||
|
return (0);
|
||||||
|
}
|
||||||
|
|
||||||
|
static int
|
||||||
|
jz4780_clk_pll_recalc_freq(struct clknode *clk, uint64_t *freq)
|
||||||
|
{
|
||||||
|
struct jz4780_clk_pll_sc *sc;
|
||||||
|
uint32_t reg, m, n, od;
|
||||||
|
|
||||||
|
sc = clknode_get_softc(clk);
|
||||||
|
reg = CLK_RD_4(sc, sc->clk_reg);
|
||||||
|
|
||||||
|
/* Check for PLL enabled status */
|
||||||
|
if (REG_GET(reg, CGU_PLL_EN) == 0) {
|
||||||
|
*freq = 0;
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Return parent frequency if PPL is being bypassed */
|
||||||
|
if (REG_GET(reg, CGU_PLL_BP) != 0)
|
||||||
|
return 0;
|
||||||
|
|
||||||
|
m = REG_GET(reg, CGU_PLL_M) + 1;
|
||||||
|
n = REG_GET(reg, CGU_PLL_N) + 1;
|
||||||
|
od = REG_GET(reg, CGU_PLL_OD) + 1;
|
||||||
|
|
||||||
|
/* Sanity check values */
|
||||||
|
if (m == 0 || n == 0 || od == 0) {
|
||||||
|
*freq = 0;
|
||||||
|
return (EINVAL);
|
||||||
|
}
|
||||||
|
|
||||||
|
*freq = ((*freq / n) * m) / od;
|
||||||
|
return (0);
|
||||||
|
}
|
||||||
|
|
||||||
|
#define MHZ (1000 * 1000)
|
||||||
|
#define PLL_TIMEOUT 100
|
||||||
|
|
||||||
|
static int
|
||||||
|
jz4780_clk_pll_wait_lock(struct jz4780_clk_pll_sc *sc)
|
||||||
|
{
|
||||||
|
int i;
|
||||||
|
|
||||||
|
for (i = 0; i < PLL_TIMEOUT; i++) {
|
||||||
|
if (CLK_RD_4(sc, sc->clk_reg) & REG_VAL(CGU_PLL_LOCK, 1))
|
||||||
|
return (0);
|
||||||
|
DELAY(1000);
|
||||||
|
}
|
||||||
|
return (ETIMEDOUT);
|
||||||
|
}
|
||||||
|
|
||||||
|
static int
|
||||||
|
jz4780_clk_pll_set_freq(struct clknode *clk, uint64_t fin,
|
||||||
|
uint64_t *fout, int flags, int *stop)
|
||||||
|
{
|
||||||
|
struct jz4780_clk_pll_sc *sc;
|
||||||
|
uint32_t reg, m, n, od;
|
||||||
|
int rv;
|
||||||
|
|
||||||
|
sc = clknode_get_softc(clk);
|
||||||
|
|
||||||
|
/* Should be able to figure all clocks with m & n only */
|
||||||
|
od = 1;
|
||||||
|
|
||||||
|
m = MIN((uint32_t)(*fout / MHZ), (1u << CGU_PLL_M_WIDTH));
|
||||||
|
m = MIN(m, 1);
|
||||||
|
|
||||||
|
n = MIN((uint32_t)(fin / MHZ), (1u << CGU_PLL_N_WIDTH));
|
||||||
|
n = MIN(n, 1);
|
||||||
|
|
||||||
|
if (flags & CLK_SET_DRYRUN) {
|
||||||
|
if (((flags & (CLK_SET_ROUND_UP | CLK_SET_ROUND_DOWN)) == 0) &&
|
||||||
|
(*fout != (((fin / n) * m) / od)))
|
||||||
|
return (ERANGE);
|
||||||
|
|
||||||
|
*fout = ((fin / n) * m) / od;
|
||||||
|
return (0);
|
||||||
|
}
|
||||||
|
|
||||||
|
CLK_LOCK(sc);
|
||||||
|
reg = CLK_RD_4(sc, sc->clk_reg);
|
||||||
|
|
||||||
|
/* Set the calculated values */
|
||||||
|
reg = REG_SET(reg, CGU_PLL_M, m - 1);
|
||||||
|
reg = REG_SET(reg, CGU_PLL_N, n - 1);
|
||||||
|
reg = REG_SET(reg, CGU_PLL_OD, od - 1);
|
||||||
|
|
||||||
|
/* Enable the PLL */
|
||||||
|
reg = REG_SET(reg, CGU_PLL_EN, 1);
|
||||||
|
reg = REG_SET(reg, CGU_PLL_BP, 0);
|
||||||
|
|
||||||
|
/* Initiate the change */
|
||||||
|
CLK_WR_4(sc, sc->clk_reg, reg);
|
||||||
|
|
||||||
|
/* Wait for PLL to lock */
|
||||||
|
rv = jz4780_clk_pll_wait_lock(sc);
|
||||||
|
CLK_UNLOCK(sc);
|
||||||
|
if (rv != 0)
|
||||||
|
return (rv);
|
||||||
|
|
||||||
|
*fout = ((fin / n) * m) / od;
|
||||||
|
return (0);
|
||||||
|
}
|
||||||
|
|
||||||
|
int jz4780_clk_pll_register(struct clkdom *clkdom,
|
||||||
|
struct clknode_init_def *clkdef, struct mtx *dev_mtx,
|
||||||
|
struct resource *mem_res, uint32_t mem_reg)
|
||||||
|
{
|
||||||
|
struct clknode *clk;
|
||||||
|
struct jz4780_clk_pll_sc *sc;
|
||||||
|
|
||||||
|
clk = clknode_create(clkdom, &jz4780_clk_pll_class, clkdef);
|
||||||
|
if (clk == NULL)
|
||||||
|
return (1);
|
||||||
|
|
||||||
|
sc = clknode_get_softc(clk);
|
||||||
|
sc->clk_mtx = dev_mtx;
|
||||||
|
sc->clk_res = mem_res;
|
||||||
|
sc->clk_reg = mem_reg;
|
||||||
|
clknode_register(clkdom, clk);
|
||||||
|
return (0);
|
||||||
|
}
|
831
sys/mips/ingenic/jz4780_clock.c
Normal file
831
sys/mips/ingenic/jz4780_clock.c
Normal file
@ -0,0 +1,831 @@
|
|||||||
|
/*-
|
||||||
|
* Copyright 2015 Alexander Kabaev <kan@FreeBSD.org>
|
||||||
|
* All rights reserved.
|
||||||
|
*
|
||||||
|
* Redistribution and use in source and binary forms, with or without
|
||||||
|
* modification, are permitted provided that the following conditions
|
||||||
|
* are met:
|
||||||
|
* 1. Redistributions of source code must retain the above copyright
|
||||||
|
* notice, this list of conditions and the following disclaimer.
|
||||||
|
* 2. Redistributions in binary form must reproduce the above copyright
|
||||||
|
* notice, this list of conditions and the following disclaimer in the
|
||||||
|
* documentation and/or other materials provided with the distribution.
|
||||||
|
*
|
||||||
|
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
|
||||||
|
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||||
|
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
||||||
|
* ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
|
||||||
|
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
|
||||||
|
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
|
||||||
|
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
|
||||||
|
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
|
||||||
|
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
|
||||||
|
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
|
||||||
|
* SUCH DAMAGE.
|
||||||
|
*/
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Ingenic JZ4780 CGU driver.
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include <sys/cdefs.h>
|
||||||
|
__FBSDID("$FreeBSD$");
|
||||||
|
|
||||||
|
#include <sys/param.h>
|
||||||
|
#include <sys/systm.h>
|
||||||
|
#include <sys/conf.h>
|
||||||
|
#include <sys/bus.h>
|
||||||
|
#include <sys/kernel.h>
|
||||||
|
#include <sys/module.h>
|
||||||
|
#include <sys/lock.h>
|
||||||
|
#include <sys/mutex.h>
|
||||||
|
#include <sys/resource.h>
|
||||||
|
#include <sys/rman.h>
|
||||||
|
|
||||||
|
#include <machine/bus.h>
|
||||||
|
|
||||||
|
#include <dev/fdt/fdt_common.h>
|
||||||
|
#include <dev/ofw/ofw_bus.h>
|
||||||
|
#include <dev/ofw/ofw_bus_subr.h>
|
||||||
|
|
||||||
|
#include <mips/ingenic/jz4780_clk.h>
|
||||||
|
#include <mips/ingenic/jz4780_regs.h>
|
||||||
|
#include <mips/ingenic/jz4780_clock.h>
|
||||||
|
|
||||||
|
#include "clkdev_if.h"
|
||||||
|
|
||||||
|
#include <gnu/dts/include/dt-bindings/clock/jz4780-cgu.h>
|
||||||
|
|
||||||
|
/**********************************************************************
|
||||||
|
* JZ4780 CGU clock domain
|
||||||
|
**********************************************************************/
|
||||||
|
struct jz4780_clock_softc {
|
||||||
|
device_t dev;
|
||||||
|
struct resource *res[1];
|
||||||
|
struct mtx mtx;
|
||||||
|
struct clkdom *clkdom;
|
||||||
|
};
|
||||||
|
|
||||||
|
static struct resource_spec jz4780_clock_spec[] = {
|
||||||
|
{ SYS_RES_MEMORY, 0, RF_ACTIVE },
|
||||||
|
{ -1, 0 }
|
||||||
|
};
|
||||||
|
|
||||||
|
struct jz4780_clk_pll_def {
|
||||||
|
uint16_t clk_id;
|
||||||
|
uint16_t clk_reg;
|
||||||
|
const char *clk_name;
|
||||||
|
const char *clk_pname[1];
|
||||||
|
};
|
||||||
|
|
||||||
|
#define PLL(_id, cname, pname, reg) { \
|
||||||
|
.clk_id = _id, \
|
||||||
|
.clk_reg = reg, \
|
||||||
|
.clk_name = cname, \
|
||||||
|
.clk_pname[0] = pname, \
|
||||||
|
}
|
||||||
|
|
||||||
|
struct jz4780_clk_gate_def {
|
||||||
|
uint16_t clk_id;
|
||||||
|
uint16_t clk_bit;
|
||||||
|
const char *clk_name;
|
||||||
|
const char *clk_pname[1];
|
||||||
|
};
|
||||||
|
|
||||||
|
#define GATE(_id, cname, pname, bit) { \
|
||||||
|
.clk_id = _id, \
|
||||||
|
.clk_bit = bit, \
|
||||||
|
.clk_name = cname, \
|
||||||
|
.clk_pname[0] = pname, \
|
||||||
|
}
|
||||||
|
|
||||||
|
#define MUX(reg, shift, bits, map) \
|
||||||
|
.clk_mux.mux_reg = (reg), \
|
||||||
|
.clk_mux.mux_shift = (shift), \
|
||||||
|
.clk_mux.mux_bits = (bits), \
|
||||||
|
.clk_mux.mux_map = (map),
|
||||||
|
#define NO_MUX
|
||||||
|
|
||||||
|
#define DIV(reg, shift, lg, bits, ce, st, bb) \
|
||||||
|
.clk_div.div_reg = (reg), \
|
||||||
|
.clk_div.div_shift = (shift), \
|
||||||
|
.clk_div.div_bits = (bits), \
|
||||||
|
.clk_div.div_lg = (lg), \
|
||||||
|
.clk_div.div_ce_bit = (ce), \
|
||||||
|
.clk_div.div_st_bit = (st), \
|
||||||
|
.clk_div.div_busy_bit = (bb),
|
||||||
|
#define NO_DIV \
|
||||||
|
|
||||||
|
#define GATEBIT(bit) \
|
||||||
|
.clk_gate_bit = (bit),
|
||||||
|
#define NO_GATE \
|
||||||
|
.clk_gate_bit = (-1),
|
||||||
|
|
||||||
|
#define PLIST(pnames...) \
|
||||||
|
.clk_pnames = { pnames },
|
||||||
|
|
||||||
|
#define GENCLK(id, name, type, parents, mux, div, gt) { \
|
||||||
|
.clk_id = id, \
|
||||||
|
.clk_type = type, \
|
||||||
|
.clk_name = name, \
|
||||||
|
parents \
|
||||||
|
mux \
|
||||||
|
div \
|
||||||
|
gt \
|
||||||
|
}
|
||||||
|
|
||||||
|
/* PLL definitions */
|
||||||
|
static struct jz4780_clk_pll_def pll_clks[] = {
|
||||||
|
PLL(JZ4780_CLK_APLL, "apll", "ext", JZ_CPAPCR),
|
||||||
|
PLL(JZ4780_CLK_MPLL, "mpll", "ext", JZ_CPMPCR),
|
||||||
|
PLL(JZ4780_CLK_EPLL, "epll", "ext", JZ_CPEPCR),
|
||||||
|
PLL(JZ4780_CLK_VPLL, "vpll", "ext", JZ_CPVPCR),
|
||||||
|
};
|
||||||
|
|
||||||
|
/* OTG PHY clock (reuse gate def structure */
|
||||||
|
static struct jz4780_clk_gate_def otg_clks[] = {
|
||||||
|
GATE(JZ4780_CLK_OTGPHY, "otg_phy", "ext", 0),
|
||||||
|
};
|
||||||
|
|
||||||
|
static const struct jz4780_clk_descr gen_clks[] = {
|
||||||
|
GENCLK(JZ4780_CLK_SCLKA, "sclk_a", CLK_MASK_MUX,
|
||||||
|
PLIST("apll", "ext", "rtc"),
|
||||||
|
MUX(JZ_CPCCR, 30, 2, 0x7),
|
||||||
|
NO_DIV,
|
||||||
|
NO_GATE
|
||||||
|
),
|
||||||
|
|
||||||
|
GENCLK(JZ4780_CLK_CPUMUX, "cpumux", CLK_MASK_MUX,
|
||||||
|
PLIST("sclk_a", "mpll", "epll"),
|
||||||
|
MUX(JZ_CPCCR, 28, 2, 0x7),
|
||||||
|
NO_DIV,
|
||||||
|
NO_GATE
|
||||||
|
),
|
||||||
|
|
||||||
|
GENCLK(JZ4780_CLK_CPU, "cpu", CLK_MASK_DIV,
|
||||||
|
PLIST("cpumux"),
|
||||||
|
NO_MUX,
|
||||||
|
DIV(JZ_CPCCR, 0, 0, 4, 22, -1, -1),
|
||||||
|
NO_GATE
|
||||||
|
),
|
||||||
|
|
||||||
|
GENCLK(JZ4780_CLK_L2CACHE, "l2cache", CLK_MASK_DIV,
|
||||||
|
PLIST("cpumux"),
|
||||||
|
NO_MUX,
|
||||||
|
DIV(JZ_CPCCR, 4, 0, 4, -1, -1, -1),
|
||||||
|
NO_GATE
|
||||||
|
),
|
||||||
|
|
||||||
|
GENCLK(JZ4780_CLK_AHB0, "ahb0", CLK_MASK_MUX | CLK_MASK_DIV,
|
||||||
|
PLIST("sclk_a", "mpll", "epll"),
|
||||||
|
MUX(JZ_CPCCR, 26, 2, 0x7),
|
||||||
|
DIV(JZ_CPCCR, 8, 0, 4, 21, -1, -1),
|
||||||
|
NO_GATE
|
||||||
|
),
|
||||||
|
|
||||||
|
GENCLK(JZ4780_CLK_AHB2PMUX, "ahb2_apb_mux", CLK_MASK_MUX,
|
||||||
|
PLIST("sclk_a", "mpll", "rtc"),
|
||||||
|
MUX(JZ_CPCCR, 24, 2, 0x7),
|
||||||
|
NO_DIV,
|
||||||
|
NO_GATE
|
||||||
|
),
|
||||||
|
|
||||||
|
GENCLK(JZ4780_CLK_AHB2, "ahb2", CLK_MASK_DIV,
|
||||||
|
PLIST("ahb2_apb_mux"),
|
||||||
|
NO_MUX,
|
||||||
|
DIV(JZ_CPCCR, 12, 0, 4, 20, -1, -1),
|
||||||
|
NO_GATE
|
||||||
|
),
|
||||||
|
|
||||||
|
GENCLK(JZ4780_CLK_PCLK, "pclk", CLK_MASK_DIV,
|
||||||
|
PLIST("ahb2_apb_mux"),
|
||||||
|
NO_MUX,
|
||||||
|
DIV(JZ_CPCCR, 16, 0, 4, 20, -1, -1),
|
||||||
|
NO_GATE
|
||||||
|
),
|
||||||
|
|
||||||
|
GENCLK(JZ4780_CLK_DDR, "ddr", CLK_MASK_MUX | CLK_MASK_DIV,
|
||||||
|
PLIST("sclk_a", "mpll"),
|
||||||
|
MUX(JZ_DDCDR, 30, 2, 0x6),
|
||||||
|
DIV(JZ_DDCDR, 0, 0, 4, 29, 28, 27),
|
||||||
|
NO_GATE
|
||||||
|
),
|
||||||
|
|
||||||
|
GENCLK(JZ4780_CLK_VPU, "vpu", CLK_MASK_MUX | CLK_MASK_DIV | CLK_MASK_GATE,
|
||||||
|
PLIST("sclk_a", "mpll", "epll"),
|
||||||
|
MUX(JZ_VPUCDR, 30, 2, 0xe),
|
||||||
|
DIV(JZ_VPUCDR, 0, 0, 4, 29, 28, 27),
|
||||||
|
GATEBIT(32 + 2)
|
||||||
|
),
|
||||||
|
|
||||||
|
GENCLK(JZ4780_CLK_I2SPLL, "i2s_pll", CLK_MASK_MUX | CLK_MASK_DIV,
|
||||||
|
PLIST("sclk_a", "epll"),
|
||||||
|
MUX(JZ_I2SCDR, 30, 1, 0xc),
|
||||||
|
DIV(JZ_I2SCDR, 0, 0, 8, 29, 28, 27),
|
||||||
|
NO_GATE
|
||||||
|
),
|
||||||
|
|
||||||
|
GENCLK(JZ4780_CLK_I2S, "i2s", CLK_MASK_MUX,
|
||||||
|
PLIST("ext", "i2s_pll"),
|
||||||
|
MUX(JZ_I2SCDR, 31, 1, 0xc),
|
||||||
|
NO_DIV,
|
||||||
|
NO_GATE
|
||||||
|
),
|
||||||
|
|
||||||
|
GENCLK(JZ4780_CLK_LCD0PIXCLK, "lcd0pixclk", CLK_MASK_MUX | CLK_MASK_DIV,
|
||||||
|
PLIST("sclk_a", "mpll", "vpll"),
|
||||||
|
MUX(JZ_LP0CDR, 30, 2, 0xe),
|
||||||
|
DIV(JZ_LP0CDR, 0, 0, 8, 28, 27, 26),
|
||||||
|
NO_GATE
|
||||||
|
),
|
||||||
|
|
||||||
|
GENCLK(JZ4780_CLK_LCD1PIXCLK, "lcd1pixclk", CLK_MASK_MUX | CLK_MASK_DIV,
|
||||||
|
PLIST("sclk_a", "mpll", "vpll"),
|
||||||
|
MUX(JZ_LP1CDR, 30, 2, 0xe),
|
||||||
|
DIV(JZ_LP1CDR, 0, 0, 8, 28, 27, 26),
|
||||||
|
NO_GATE
|
||||||
|
),
|
||||||
|
|
||||||
|
GENCLK(JZ4780_CLK_MSCMUX, "msc_mux", CLK_MASK_MUX,
|
||||||
|
PLIST("sclk_a", "mpll"),
|
||||||
|
MUX(JZ_MSC0CDR, 30, 2, 0x6),
|
||||||
|
NO_DIV,
|
||||||
|
NO_GATE
|
||||||
|
),
|
||||||
|
|
||||||
|
GENCLK(JZ4780_CLK_MSC0, "msc0", CLK_MASK_DIV | CLK_MASK_GATE,
|
||||||
|
PLIST("msc_mux"),
|
||||||
|
NO_MUX,
|
||||||
|
DIV(JZ_MSC0CDR, 0, 1, 8, 29, 28, 27),
|
||||||
|
GATEBIT(3)
|
||||||
|
),
|
||||||
|
|
||||||
|
GENCLK(JZ4780_CLK_MSC1, "msc1", CLK_MASK_DIV | CLK_MASK_GATE,
|
||||||
|
PLIST("msc_mux"),
|
||||||
|
NO_MUX,
|
||||||
|
DIV(JZ_MSC1CDR, 0, 1, 8, 29, 28, 27),
|
||||||
|
GATEBIT(11)
|
||||||
|
),
|
||||||
|
|
||||||
|
GENCLK(JZ4780_CLK_MSC2, "msc2", CLK_MASK_DIV | CLK_MASK_GATE,
|
||||||
|
PLIST("msc_mux"),
|
||||||
|
NO_MUX,
|
||||||
|
DIV(JZ_MSC2CDR, 0, 1, 8, 29, 28, 27),
|
||||||
|
GATEBIT(12)
|
||||||
|
),
|
||||||
|
|
||||||
|
GENCLK(JZ4780_CLK_UHC, "uhc", CLK_MASK_MUX | CLK_MASK_DIV | CLK_MASK_GATE,
|
||||||
|
PLIST("sclk_a", "mpll", "epll", "otg_phy"),
|
||||||
|
MUX(JZ_UHCCDR, 30, 2, 0xf),
|
||||||
|
DIV(JZ_UHCCDR, 0, 0, 8, 29, 28, 27),
|
||||||
|
GATEBIT(24)
|
||||||
|
),
|
||||||
|
|
||||||
|
GENCLK(JZ4780_CLK_SSIPLL, "ssi_pll", CLK_MASK_MUX | CLK_MASK_DIV,
|
||||||
|
PLIST("sclk_a", "mpll"),
|
||||||
|
MUX(JZ_SSICDR, 30, 1, 0xc),
|
||||||
|
DIV(JZ_SSICDR, 0, 0, 8, 29, 28, 27),
|
||||||
|
NO_GATE
|
||||||
|
),
|
||||||
|
|
||||||
|
GENCLK(JZ4780_CLK_SSI, "ssi", CLK_MASK_MUX,
|
||||||
|
PLIST("ext", "ssi_pll"),
|
||||||
|
MUX(JZ_SSICDR, 31, 1, 0xc),
|
||||||
|
NO_DIV,
|
||||||
|
NO_GATE
|
||||||
|
),
|
||||||
|
|
||||||
|
GENCLK(JZ4780_CLK_CIMMCLK, "cim_mclk", CLK_MASK_MUX | CLK_MASK_DIV,
|
||||||
|
PLIST("sclk_a", "mpll"),
|
||||||
|
MUX(JZ_CIMCDR, 31, 1, 0xc),
|
||||||
|
DIV(JZ_CIMCDR, 0, 0, 8, 30, 29, 28),
|
||||||
|
NO_GATE
|
||||||
|
),
|
||||||
|
|
||||||
|
GENCLK(JZ4780_CLK_PCMPLL, "pcm_pll", CLK_MASK_MUX | CLK_MASK_DIV,
|
||||||
|
PLIST("sclk_a", "mpll", "epll", "vpll"),
|
||||||
|
MUX(JZ_PCMCDR, 29, 2, 0xf),
|
||||||
|
DIV(JZ_PCMCDR, 0, 0, 8, 28, 27, 26),
|
||||||
|
NO_GATE
|
||||||
|
),
|
||||||
|
|
||||||
|
GENCLK(JZ4780_CLK_PCM, "pcm", CLK_MASK_MUX | CLK_MASK_GATE,
|
||||||
|
PLIST("ext", "pcm_pll"),
|
||||||
|
MUX(JZ_PCMCDR, 31, 1, 0xc),
|
||||||
|
NO_DIV,
|
||||||
|
GATEBIT(32 + 3)
|
||||||
|
),
|
||||||
|
|
||||||
|
GENCLK(JZ4780_CLK_GPU, "gpu", CLK_MASK_MUX | CLK_MASK_DIV | CLK_MASK_GATE,
|
||||||
|
PLIST("sclk_a", "mpll", "epll"),
|
||||||
|
MUX(JZ_GPUCDR, 30, 2, 0x7),
|
||||||
|
DIV(JZ_GPUCDR, 0, 0, 4, 29, 28, 27),
|
||||||
|
GATEBIT(32 + 4)
|
||||||
|
),
|
||||||
|
|
||||||
|
GENCLK(JZ4780_CLK_HDMI, "hdmi", CLK_MASK_MUX | CLK_MASK_DIV | CLK_MASK_GATE,
|
||||||
|
PLIST("sclk_a", "mpll", "vpll"),
|
||||||
|
MUX(JZ_HDMICDR, 30, 2, 0xe),
|
||||||
|
DIV(JZ_HDMICDR, 0, 0, 8, 29, 28, 26),
|
||||||
|
GATEBIT(32 + 9)
|
||||||
|
),
|
||||||
|
|
||||||
|
GENCLK(JZ4780_CLK_BCH, "bch", CLK_MASK_MUX | CLK_MASK_DIV | CLK_MASK_GATE,
|
||||||
|
PLIST("sclk_a", "mpll", "epll"),
|
||||||
|
MUX(JZ_BCHCDR, 30, 2, 0x7),
|
||||||
|
DIV(JZ_BCHCDR, 0, 0, 4, 29, 28, 27),
|
||||||
|
GATEBIT(1)
|
||||||
|
),
|
||||||
|
};
|
||||||
|
|
||||||
|
static struct jz4780_clk_gate_def gate_clks[] = {
|
||||||
|
GATE(JZ4780_CLK_NEMC, "nemc", "ahb2", 0),
|
||||||
|
GATE(JZ4780_CLK_OTG0, "otg0", "ext", 2),
|
||||||
|
GATE(JZ4780_CLK_SSI0, "ssi0", "ssi", 4),
|
||||||
|
GATE(JZ4780_CLK_SMB0, "smb0", "pclk", 5),
|
||||||
|
GATE(JZ4780_CLK_SMB1, "smb1", "pclk", 6),
|
||||||
|
GATE(JZ4780_CLK_SCC, "scc", "ext", 7),
|
||||||
|
GATE(JZ4780_CLK_AIC, "aic", "ext", 8),
|
||||||
|
GATE(JZ4780_CLK_TSSI0, "tssi0", "ext", 9),
|
||||||
|
GATE(JZ4780_CLK_OWI, "owi", "ext", 10),
|
||||||
|
GATE(JZ4780_CLK_KBC, "kbc", "ext", 13),
|
||||||
|
GATE(JZ4780_CLK_SADC, "sadc", "ext", 14),
|
||||||
|
GATE(JZ4780_CLK_UART0, "uart0", "ext", 15),
|
||||||
|
GATE(JZ4780_CLK_UART1, "uart1", "ext", 16),
|
||||||
|
GATE(JZ4780_CLK_UART2, "uart2", "ext", 17),
|
||||||
|
GATE(JZ4780_CLK_UART3, "uart3", "ext", 18),
|
||||||
|
GATE(JZ4780_CLK_SSI1, "ssi1", "ssi", 19),
|
||||||
|
GATE(JZ4780_CLK_SSI2, "ssi2", "ssi", 20),
|
||||||
|
GATE(JZ4780_CLK_PDMA, "pdma", "ext", 21),
|
||||||
|
GATE(JZ4780_CLK_GPS, "gps", "ext", 22),
|
||||||
|
GATE(JZ4780_CLK_MAC, "mac", "ext", 23),
|
||||||
|
GATE(JZ4780_CLK_SMB2, "smb2", "pclk", 25),
|
||||||
|
GATE(JZ4780_CLK_CIM, "cim", "ext", 26),
|
||||||
|
GATE(JZ4780_CLK_LCD, "lcd", "ext", 28),
|
||||||
|
GATE(JZ4780_CLK_TVE, "tve", "lcd", 27),
|
||||||
|
GATE(JZ4780_CLK_IPU, "ipu", "ext", 29),
|
||||||
|
GATE(JZ4780_CLK_DDR0, "ddr0", "ddr", 30),
|
||||||
|
GATE(JZ4780_CLK_DDR1, "ddr1", "ddr", 31),
|
||||||
|
GATE(JZ4780_CLK_SMB3, "smb3", "pclk", 32 + 0),
|
||||||
|
GATE(JZ4780_CLK_TSSI1, "tssi1", "ext", 32 + 1),
|
||||||
|
GATE(JZ4780_CLK_COMPRESS, "compress", "ext", 32 + 5),
|
||||||
|
GATE(JZ4780_CLK_AIC1, "aic1", "ext", 32 + 6),
|
||||||
|
GATE(JZ4780_CLK_GPVLC, "gpvlc", "ext", 32 + 7),
|
||||||
|
GATE(JZ4780_CLK_OTG1, "otg1", "ext", 32 + 8),
|
||||||
|
GATE(JZ4780_CLK_UART4, "uart4", "ext", 32 + 10),
|
||||||
|
GATE(JZ4780_CLK_AHBMON, "ahb_mon", "ext", 32 + 11),
|
||||||
|
GATE(JZ4780_CLK_SMB4, "smb4", "pclk", 32 + 12),
|
||||||
|
GATE(JZ4780_CLK_DES, "des", "ext", 32 + 13),
|
||||||
|
GATE(JZ4780_CLK_X2D, "x2d", "ext", 32 + 14),
|
||||||
|
GATE(JZ4780_CLK_CORE1, "core1", "cpu", 32 + 15),
|
||||||
|
};
|
||||||
|
|
||||||
|
static int
|
||||||
|
jz4780_clock_register(struct jz4780_clock_softc *sc)
|
||||||
|
{
|
||||||
|
int i, ret;
|
||||||
|
|
||||||
|
/* Register PLLs */
|
||||||
|
for (i = 0; i < nitems(pll_clks); i++) {
|
||||||
|
struct clknode_init_def clkdef;
|
||||||
|
|
||||||
|
clkdef.id = pll_clks[i].clk_id;
|
||||||
|
clkdef.name = __DECONST(char *, pll_clks[i].clk_name);
|
||||||
|
clkdef.parent_names = pll_clks[i].clk_pname;
|
||||||
|
clkdef.parent_cnt = 1;
|
||||||
|
clkdef.flags = CLK_NODE_STATIC_STRINGS;
|
||||||
|
|
||||||
|
ret = jz4780_clk_pll_register(sc->clkdom, &clkdef, &sc->mtx,
|
||||||
|
sc->res[0], pll_clks[i].clk_reg);
|
||||||
|
if (ret != 0)
|
||||||
|
return (ret);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Register OTG clock */
|
||||||
|
for (i = 0; i < nitems(otg_clks); i++) {
|
||||||
|
struct clknode_init_def clkdef;
|
||||||
|
|
||||||
|
clkdef.id = otg_clks[i].clk_id;
|
||||||
|
clkdef.name = __DECONST(char *, otg_clks[i].clk_name);
|
||||||
|
clkdef.parent_names = otg_clks[i].clk_pname;
|
||||||
|
clkdef.parent_cnt = 1;
|
||||||
|
clkdef.flags = CLK_NODE_STATIC_STRINGS;
|
||||||
|
|
||||||
|
ret = jz4780_clk_otg_register(sc->clkdom, &clkdef, &sc->mtx,
|
||||||
|
sc->res[0]);
|
||||||
|
if (ret != 0)
|
||||||
|
return (ret);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Register muxes and divisors */
|
||||||
|
for (i = 0; i < nitems(gen_clks); i++) {
|
||||||
|
ret = jz4780_clk_gen_register(sc->clkdom, &gen_clks[i],
|
||||||
|
&sc->mtx, sc->res[0]);
|
||||||
|
if (ret != 0)
|
||||||
|
return (ret);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Register simple gates */
|
||||||
|
for (i = 0; i < nitems(gate_clks); i++) {
|
||||||
|
struct clk_gate_def gatedef;
|
||||||
|
|
||||||
|
gatedef.clkdef.id = gate_clks[i].clk_id;
|
||||||
|
gatedef.clkdef.name = __DECONST(char *, gate_clks[i].clk_name);
|
||||||
|
gatedef.clkdef.parent_names = gate_clks[i].clk_pname;
|
||||||
|
gatedef.clkdef.parent_cnt = 1;
|
||||||
|
gatedef.clkdef.flags = CLK_NODE_STATIC_STRINGS;
|
||||||
|
|
||||||
|
if (gate_clks[i].clk_bit < 32) {
|
||||||
|
gatedef.offset = JZ_CLKGR0;
|
||||||
|
gatedef.shift = gate_clks[i].clk_bit;
|
||||||
|
} else {
|
||||||
|
gatedef.offset = JZ_CLKGR1;
|
||||||
|
gatedef.shift = gate_clks[i].clk_bit - 32;
|
||||||
|
}
|
||||||
|
gatedef.mask = 1;
|
||||||
|
gatedef.on_value = 0;
|
||||||
|
gatedef.off_value = 1;
|
||||||
|
gatedef.gate_flags = 0;
|
||||||
|
|
||||||
|
ret = clknode_gate_register(sc->clkdom, &gatedef);
|
||||||
|
if (ret != 0)
|
||||||
|
return (ret);
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
return (0);
|
||||||
|
}
|
||||||
|
|
||||||
|
static int
|
||||||
|
jz4780_clock_fixup(struct jz4780_clock_softc *sc)
|
||||||
|
{
|
||||||
|
struct clknode *clk_uhc;
|
||||||
|
int ret;
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Make UHC mux use MPLL as the source. It defaults to OTG_PHY
|
||||||
|
* and that somehow just does not work.
|
||||||
|
*/
|
||||||
|
clkdom_xlock(sc->clkdom);
|
||||||
|
|
||||||
|
/* Assume the worst */
|
||||||
|
ret = ENXIO;
|
||||||
|
|
||||||
|
clk_uhc = clknode_find_by_id(sc->clkdom, JZ4780_CLK_UHC);
|
||||||
|
if (clk_uhc != NULL) {
|
||||||
|
ret = clknode_set_parent_by_name(clk_uhc, "mpll");
|
||||||
|
if (ret != 0)
|
||||||
|
device_printf(sc->dev,
|
||||||
|
"unable to reparent uhc clock\n");
|
||||||
|
else
|
||||||
|
ret = clknode_set_freq(clk_uhc, 48000000, 0, 0);
|
||||||
|
if (ret != 0)
|
||||||
|
device_printf(sc->dev, "unable to init uhc clock\n");
|
||||||
|
} else
|
||||||
|
device_printf(sc->dev, "unable to lookup uhc clock\n");
|
||||||
|
|
||||||
|
clkdom_unlock(sc->clkdom);
|
||||||
|
return (ret);
|
||||||
|
}
|
||||||
|
|
||||||
|
#define CGU_LOCK(sc) mtx_lock(&(sc)->mtx)
|
||||||
|
#define CGU_UNLOCK(sc) mtx_unlock(&(sc)->mtx)
|
||||||
|
#define CGU_LOCK_INIT(sc) \
|
||||||
|
mtx_init(&(sc)->mtx, device_get_nameunit((sc)->dev), \
|
||||||
|
"jz4780-cgu", MTX_DEF)
|
||||||
|
#define CGU_LOCK_DESTROY(sc) mtx_destroy(&(sc)->mtx);
|
||||||
|
|
||||||
|
#define CSR_WRITE_4(sc, reg, val) bus_write_4((sc)->res[0], (reg), (val))
|
||||||
|
#define CSR_READ_4(sc, reg) bus_read_4((sc)->res[0], (reg))
|
||||||
|
|
||||||
|
static int
|
||||||
|
jz4780_clock_probe(device_t dev)
|
||||||
|
{
|
||||||
|
|
||||||
|
if (!ofw_bus_status_okay(dev))
|
||||||
|
return (ENXIO);
|
||||||
|
|
||||||
|
if (!ofw_bus_is_compatible(dev, "ingenic,jz4780-cgu"))
|
||||||
|
return (ENXIO);
|
||||||
|
|
||||||
|
device_set_desc(dev, "Ingenic jz4780 CGU");
|
||||||
|
|
||||||
|
return (BUS_PROBE_DEFAULT);
|
||||||
|
}
|
||||||
|
|
||||||
|
static int
|
||||||
|
jz4780_clock_attach(device_t dev)
|
||||||
|
{
|
||||||
|
struct jz4780_clock_softc *sc;
|
||||||
|
|
||||||
|
sc = device_get_softc(dev);
|
||||||
|
if (bus_alloc_resources(dev, jz4780_clock_spec, sc->res)) {
|
||||||
|
device_printf(dev, "could not allocate resources for device\n");
|
||||||
|
return (ENXIO);
|
||||||
|
}
|
||||||
|
|
||||||
|
sc->dev = dev;
|
||||||
|
CGU_LOCK_INIT(sc);
|
||||||
|
|
||||||
|
sc->clkdom = clkdom_create(dev);
|
||||||
|
if (sc->clkdom == NULL)
|
||||||
|
goto fail;
|
||||||
|
if (jz4780_clock_register(sc) != 0)
|
||||||
|
goto fail;
|
||||||
|
if (clkdom_finit(sc->clkdom) != 0)
|
||||||
|
goto fail;
|
||||||
|
if (jz4780_clock_fixup(sc) != 0)
|
||||||
|
goto fail;
|
||||||
|
if (bootverbose)
|
||||||
|
clkdom_dump(sc->clkdom);
|
||||||
|
|
||||||
|
return (0);
|
||||||
|
fail:
|
||||||
|
bus_release_resources(dev, jz4780_clock_spec, sc->res);
|
||||||
|
CGU_LOCK_DESTROY(sc);
|
||||||
|
|
||||||
|
return (ENXIO);
|
||||||
|
}
|
||||||
|
|
||||||
|
static int
|
||||||
|
jz4780_clock_detach(device_t dev)
|
||||||
|
{
|
||||||
|
struct jz4780_clock_softc *sc;
|
||||||
|
|
||||||
|
sc = device_get_softc(dev);
|
||||||
|
bus_release_resources(dev, jz4780_clock_spec, sc->res);
|
||||||
|
CGU_LOCK_DESTROY(sc);
|
||||||
|
|
||||||
|
return (0);
|
||||||
|
}
|
||||||
|
|
||||||
|
static int
|
||||||
|
jz4780_clock_write_4(device_t dev, bus_addr_t addr, uint32_t val)
|
||||||
|
{
|
||||||
|
struct jz4780_clock_softc *sc;
|
||||||
|
|
||||||
|
sc = device_get_softc(dev);
|
||||||
|
CSR_WRITE_4(sc, addr, val);
|
||||||
|
return (0);
|
||||||
|
}
|
||||||
|
|
||||||
|
static int
|
||||||
|
jz4780_clock_read_4(device_t dev, bus_addr_t addr, uint32_t *val)
|
||||||
|
{
|
||||||
|
struct jz4780_clock_softc *sc;
|
||||||
|
|
||||||
|
sc = device_get_softc(dev);
|
||||||
|
*val = CSR_READ_4(sc, addr);
|
||||||
|
return (0);
|
||||||
|
}
|
||||||
|
|
||||||
|
static int
|
||||||
|
jz4780_clock_modify_4(device_t dev, bus_addr_t addr, uint32_t clear_mask,
|
||||||
|
uint32_t set_mask)
|
||||||
|
{
|
||||||
|
struct jz4780_clock_softc *sc;
|
||||||
|
uint32_t val;
|
||||||
|
|
||||||
|
sc = device_get_softc(dev);
|
||||||
|
val = CSR_READ_4(sc, addr);
|
||||||
|
val &= clear_mask;
|
||||||
|
val |= set_mask;
|
||||||
|
CSR_WRITE_4(sc, addr, val);
|
||||||
|
return (0);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
jz4780_clock_device_lock(device_t dev)
|
||||||
|
{
|
||||||
|
struct jz4780_clock_softc *sc;
|
||||||
|
|
||||||
|
sc = device_get_softc(dev);
|
||||||
|
CGU_LOCK(sc);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
jz4780_clock_device_unlock(device_t dev)
|
||||||
|
{
|
||||||
|
struct jz4780_clock_softc *sc;
|
||||||
|
|
||||||
|
sc = device_get_softc(dev);
|
||||||
|
CGU_UNLOCK(sc);
|
||||||
|
}
|
||||||
|
|
||||||
|
static device_method_t jz4780_clock_methods[] = {
|
||||||
|
/* Device interface */
|
||||||
|
DEVMETHOD(device_probe, jz4780_clock_probe),
|
||||||
|
DEVMETHOD(device_attach, jz4780_clock_attach),
|
||||||
|
DEVMETHOD(device_detach, jz4780_clock_detach),
|
||||||
|
|
||||||
|
/* Clock device interface */
|
||||||
|
DEVMETHOD(clkdev_write_4, jz4780_clock_write_4),
|
||||||
|
DEVMETHOD(clkdev_read_4, jz4780_clock_read_4),
|
||||||
|
DEVMETHOD(clkdev_modify_4, jz4780_clock_modify_4),
|
||||||
|
DEVMETHOD(clkdev_device_lock, jz4780_clock_device_lock),
|
||||||
|
DEVMETHOD(clkdev_device_unlock, jz4780_clock_device_unlock),
|
||||||
|
|
||||||
|
DEVMETHOD_END
|
||||||
|
};
|
||||||
|
|
||||||
|
static driver_t jz4780_clock_driver = {
|
||||||
|
"cgu",
|
||||||
|
jz4780_clock_methods,
|
||||||
|
sizeof(struct jz4780_clock_softc),
|
||||||
|
};
|
||||||
|
|
||||||
|
static devclass_t jz4780_clock_devclass;
|
||||||
|
|
||||||
|
EARLY_DRIVER_MODULE(jz4780_clock, simplebus, jz4780_clock_driver,
|
||||||
|
jz4780_clock_devclass, 0, 0, BUS_PASS_CPU + BUS_PASS_ORDER_LATE);
|
||||||
|
|
||||||
|
static int
|
||||||
|
jz4780_ehci_clk_config(struct jz4780_clock_softc *sc)
|
||||||
|
{
|
||||||
|
clk_t phy_clk, ext_clk;
|
||||||
|
uint64_t phy_freq;
|
||||||
|
int err;
|
||||||
|
|
||||||
|
phy_clk = NULL;
|
||||||
|
ext_clk = NULL;
|
||||||
|
err = -1;
|
||||||
|
|
||||||
|
/* Set phy timing by copying it from ext */
|
||||||
|
if (clk_get_by_id(sc->dev, sc->clkdom, JZ4780_CLK_OTGPHY,
|
||||||
|
&phy_clk) != 0)
|
||||||
|
goto done;
|
||||||
|
if (clk_get_parent(phy_clk, &ext_clk) != 0)
|
||||||
|
goto done;
|
||||||
|
if (clk_get_freq(ext_clk, &phy_freq) != 0)
|
||||||
|
goto done;
|
||||||
|
if (clk_set_freq(phy_clk, phy_freq, 0) != 0)
|
||||||
|
goto done;
|
||||||
|
err = 0;
|
||||||
|
done:
|
||||||
|
clk_release(ext_clk);
|
||||||
|
clk_release(phy_clk);
|
||||||
|
|
||||||
|
return (err);
|
||||||
|
}
|
||||||
|
|
||||||
|
int
|
||||||
|
jz4780_ohci_enable(void)
|
||||||
|
{
|
||||||
|
device_t dev;
|
||||||
|
struct jz4780_clock_softc *sc;
|
||||||
|
uint32_t reg;
|
||||||
|
|
||||||
|
dev = devclass_get_device(jz4780_clock_devclass, 0);
|
||||||
|
if (dev == NULL)
|
||||||
|
return (-1);
|
||||||
|
|
||||||
|
sc = device_get_softc(dev);
|
||||||
|
CGU_LOCK(sc);
|
||||||
|
|
||||||
|
/* Do not force port1 to suspend mode */
|
||||||
|
reg = CSR_READ_4(sc, JZ_OPCR);
|
||||||
|
reg |= OPCR_SPENDN1;
|
||||||
|
CSR_WRITE_4(sc, JZ_OPCR, reg);
|
||||||
|
|
||||||
|
CGU_UNLOCK(sc);
|
||||||
|
return (0);
|
||||||
|
}
|
||||||
|
|
||||||
|
int
|
||||||
|
jz4780_ehci_enable(void)
|
||||||
|
{
|
||||||
|
device_t dev;
|
||||||
|
struct jz4780_clock_softc *sc;
|
||||||
|
uint32_t reg;
|
||||||
|
|
||||||
|
dev = devclass_get_device(jz4780_clock_devclass, 0);
|
||||||
|
if (dev == NULL)
|
||||||
|
return (-1);
|
||||||
|
|
||||||
|
sc = device_get_softc(dev);
|
||||||
|
|
||||||
|
/*
|
||||||
|
* EHCI should use MPPL as a parent, but Linux configures OTG
|
||||||
|
* clock anyway. Follow their lead blindly.
|
||||||
|
*/
|
||||||
|
if (jz4780_ehci_clk_config(sc) != 0)
|
||||||
|
return (-1);
|
||||||
|
|
||||||
|
CGU_LOCK(sc);
|
||||||
|
|
||||||
|
/* Enable OTG, should not be necessary since we use PLL clock */
|
||||||
|
reg = CSR_READ_4(sc, JZ_USBPCR);
|
||||||
|
reg &= ~(PCR_OTG_DISABLE);
|
||||||
|
CSR_WRITE_4(sc, JZ_USBPCR, reg);
|
||||||
|
|
||||||
|
/* Do not force port1 to suspend mode */
|
||||||
|
reg = CSR_READ_4(sc, JZ_OPCR);
|
||||||
|
reg |= OPCR_SPENDN1;
|
||||||
|
CSR_WRITE_4(sc, JZ_OPCR, reg);
|
||||||
|
|
||||||
|
/* D- pulldown */
|
||||||
|
reg = CSR_READ_4(sc, JZ_USBPCR1);
|
||||||
|
reg |= PCR_DMPD1;
|
||||||
|
CSR_WRITE_4(sc, JZ_USBPCR1, reg);
|
||||||
|
|
||||||
|
/* D+ pulldown */
|
||||||
|
reg = CSR_READ_4(sc, JZ_USBPCR1);
|
||||||
|
reg |= PCR_DPPD1;
|
||||||
|
CSR_WRITE_4(sc, JZ_USBPCR1, reg);
|
||||||
|
|
||||||
|
/* 16 bit bus witdth for port 1*/
|
||||||
|
reg = CSR_READ_4(sc, JZ_USBPCR1);
|
||||||
|
reg |= PCR_WORD_I_F1 | PCR_WORD_I_F0;
|
||||||
|
CSR_WRITE_4(sc, JZ_USBPCR1, reg);
|
||||||
|
|
||||||
|
/* Reset USB */
|
||||||
|
reg = CSR_READ_4(sc, JZ_USBPCR);
|
||||||
|
reg |= PCR_POR;
|
||||||
|
CSR_WRITE_4(sc, JZ_USBPCR, reg);
|
||||||
|
DELAY(1);
|
||||||
|
reg = CSR_READ_4(sc, JZ_USBPCR);
|
||||||
|
reg &= ~(PCR_POR);
|
||||||
|
CSR_WRITE_4(sc, JZ_USBPCR, reg);
|
||||||
|
|
||||||
|
/* Soft-reset USB */
|
||||||
|
reg = CSR_READ_4(sc, JZ_SRBC);
|
||||||
|
reg |= SRBC_UHC_SR;
|
||||||
|
CSR_WRITE_4(sc, JZ_SRBC, reg);
|
||||||
|
/* 300ms */
|
||||||
|
DELAY(300*hz/1000);
|
||||||
|
|
||||||
|
reg = CSR_READ_4(sc, JZ_SRBC);
|
||||||
|
reg &= ~(SRBC_UHC_SR);
|
||||||
|
CSR_WRITE_4(sc, JZ_SRBC, reg);
|
||||||
|
|
||||||
|
/* 300ms */
|
||||||
|
DELAY(300*hz/1000);
|
||||||
|
|
||||||
|
CGU_UNLOCK(sc);
|
||||||
|
return (0);
|
||||||
|
}
|
||||||
|
|
||||||
|
#define USBRESET_DETECT_TIME 0x96
|
||||||
|
|
||||||
|
int
|
||||||
|
jz4780_otg_enable(void)
|
||||||
|
{
|
||||||
|
device_t dev;
|
||||||
|
struct jz4780_clock_softc *sc;
|
||||||
|
uint32_t reg;
|
||||||
|
|
||||||
|
dev = devclass_get_device(jz4780_clock_devclass, 0);
|
||||||
|
if (dev == NULL)
|
||||||
|
return (-1);
|
||||||
|
|
||||||
|
sc = device_get_softc(dev);
|
||||||
|
|
||||||
|
CGU_LOCK(sc);
|
||||||
|
|
||||||
|
/* Select Synopsys OTG mode */
|
||||||
|
reg = CSR_READ_4(sc, JZ_USBPCR1);
|
||||||
|
reg |= PCR_SYNOPSYS;
|
||||||
|
|
||||||
|
/* Set UTMI bus width to 16 bit */
|
||||||
|
reg |= PCR_WORD_I_F0 | PCR_WORD_I_F1;
|
||||||
|
CSR_WRITE_4(sc, JZ_USBPCR1, reg);
|
||||||
|
|
||||||
|
/* Blah */
|
||||||
|
reg = CSR_READ_4(sc, JZ_USBVBFIL);
|
||||||
|
reg = REG_SET(reg, USBVBFIL_IDDIGFIL, 0);
|
||||||
|
reg = REG_SET(reg, USBVBFIL_USBVBFIL, 0);
|
||||||
|
CSR_WRITE_4(sc, JZ_USBVBFIL, reg);
|
||||||
|
|
||||||
|
/* Setup reset detect time */
|
||||||
|
reg = CSR_READ_4(sc, JZ_USBRDT);
|
||||||
|
reg = REG_SET(reg, USBRDT_USBRDT, USBRESET_DETECT_TIME);
|
||||||
|
reg |= USBRDT_VBFIL_LD_EN;
|
||||||
|
CSR_WRITE_4(sc, JZ_USBRDT, reg);
|
||||||
|
|
||||||
|
/* Setup USBPCR bits */
|
||||||
|
reg = CSR_READ_4(sc, JZ_USBPCR);
|
||||||
|
reg |= PCR_USB_MODE;
|
||||||
|
reg |= PCR_COMMONONN;
|
||||||
|
reg |= PCR_VBUSVLDEXT;
|
||||||
|
reg |= PCR_VBUSVLDEXTSEL;
|
||||||
|
reg &= ~(PCR_OTG_DISABLE);
|
||||||
|
CSR_WRITE_4(sc, JZ_USBPCR, reg);
|
||||||
|
|
||||||
|
/* Reset USB */
|
||||||
|
reg = CSR_READ_4(sc, JZ_USBPCR);
|
||||||
|
reg |= PCR_POR;
|
||||||
|
CSR_WRITE_4(sc, JZ_USBPCR, reg);
|
||||||
|
DELAY(1000);
|
||||||
|
reg = CSR_READ_4(sc, JZ_USBPCR);
|
||||||
|
reg &= ~(PCR_POR);
|
||||||
|
CSR_WRITE_4(sc, JZ_USBPCR, reg);
|
||||||
|
|
||||||
|
/* Unsuspend OTG port */
|
||||||
|
reg = CSR_READ_4(sc, JZ_OPCR);
|
||||||
|
reg |= OPCR_SPENDN0;
|
||||||
|
CSR_WRITE_4(sc, JZ_OPCR, reg);
|
||||||
|
|
||||||
|
CGU_UNLOCK(sc);
|
||||||
|
return (0);
|
||||||
|
}
|
36
sys/mips/ingenic/jz4780_clock.h
Normal file
36
sys/mips/ingenic/jz4780_clock.h
Normal file
@ -0,0 +1,36 @@
|
|||||||
|
/*-
|
||||||
|
* Copyright 2015 Alexander Kabaev <kan@FreeBSD.org>
|
||||||
|
* All rights reserved.
|
||||||
|
*
|
||||||
|
* Redistribution and use in source and binary forms, with or without
|
||||||
|
* modification, are permitted provided that the following conditions
|
||||||
|
* are met:
|
||||||
|
* 1. Redistributions of source code must retain the above copyright
|
||||||
|
* notice, this list of conditions and the following disclaimer.
|
||||||
|
* 2. Redistributions in binary form must reproduce the above copyright
|
||||||
|
* notice, this list of conditions and the following disclaimer in the
|
||||||
|
* documentation and/or other materials provided with the distribution.
|
||||||
|
*
|
||||||
|
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
|
||||||
|
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||||
|
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
||||||
|
* ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
|
||||||
|
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
|
||||||
|
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
|
||||||
|
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
|
||||||
|
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
|
||||||
|
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
|
||||||
|
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
|
||||||
|
* SUCH DAMAGE.
|
||||||
|
*
|
||||||
|
* $FreeBSD$
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef JZ4780_CLOCK_H
|
||||||
|
#define JZ4780_CLOCK_H
|
||||||
|
|
||||||
|
extern int jz4780_ehci_enable(void);
|
||||||
|
extern int jz4780_ohci_enable(void);
|
||||||
|
extern int jz4780_otg_enable(void);
|
||||||
|
|
||||||
|
#endif
|
73
sys/mips/ingenic/jz4780_cpuregs.h
Normal file
73
sys/mips/ingenic/jz4780_cpuregs.h
Normal file
@ -0,0 +1,73 @@
|
|||||||
|
/*-
|
||||||
|
* Copyright (c) 2015 Alexander Kabaev <kan@FreeBSD.org>
|
||||||
|
* All rights reserved.
|
||||||
|
*
|
||||||
|
* Redistribution and use in source and binary forms, with or without
|
||||||
|
* modification, are permitted provided that the following conditions
|
||||||
|
* are met:
|
||||||
|
* 1. Redistributions of source code must retain the above copyright
|
||||||
|
* notice, this list of conditions and the following disclaimer.
|
||||||
|
* 2. Redistributions in binary form must reproduce the above copyright
|
||||||
|
* notice, this list of conditions and the following disclaimer in the
|
||||||
|
* documentation and/or other materials provided with the distribution.
|
||||||
|
*
|
||||||
|
* THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
|
||||||
|
* ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
|
||||||
|
* TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
|
||||||
|
* PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
|
||||||
|
* BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
|
||||||
|
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
|
||||||
|
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
|
||||||
|
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
|
||||||
|
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
|
||||||
|
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
|
||||||
|
* POSSIBILITY OF SUCH DAMAGE.
|
||||||
|
*
|
||||||
|
* $FreeBSD$
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef JZ4780_CPUREGS_H
|
||||||
|
#define JZ4780_CPUREGS_H
|
||||||
|
|
||||||
|
/* Core control register */
|
||||||
|
#define JZ_CORECTL_SLP1M_SHIFT 17
|
||||||
|
#define JZ_CORECTL_SLP1M (1u << JZ_CORECTL_SLP1M_SHIFT)
|
||||||
|
#define JZ_CORECTL_SLP0M_SHIFT 16
|
||||||
|
#define JZ_CORECTL_SLP0M (1u << JZ_CORECTL_SLP0M_SHIFT)
|
||||||
|
#define JZ_CORECTL_RPC1_SHIFT 9
|
||||||
|
#define JZ_CORECTL_RPC1 (1u << JZ_CORECTL_RPC1_SHIFT)
|
||||||
|
#define JZ_CORECTL_RPC0_SHIFT 8
|
||||||
|
#define JZ_CORECTL_RPC0 (1u << JZ_CORECTL_RPC0_SHIFT)
|
||||||
|
#define JZ_CORECTL_SWRST1_SHIFT 1
|
||||||
|
#define JZ_CORECTL_SWRST1 (1u << JZ_CORECTL_SWRST1_SHIFT)
|
||||||
|
#define JZ_CORECTL_SWRST0_SHIFT 0
|
||||||
|
#define JZ_CORECTL_SWRST0 (1u << JZ_CORECTL_SWRST0_SHIFT)
|
||||||
|
|
||||||
|
/* Core status register */
|
||||||
|
#define JZ_CORESTS_SLP1_SHIFT 17
|
||||||
|
#define JZ_CORESTS_SLP1 (1u << JZ_CORESTS_SLP1_SHIFT)
|
||||||
|
#define JZ_CORESTS_SLP0_SHIFT 16
|
||||||
|
#define JZ_CORESTS_SLP0 (1u << JZ_CORESTS_SLP0_SHIFT)
|
||||||
|
#define JZ_CORESTS_IRQ1P_SHIFT 9
|
||||||
|
#define JZ_CORESTS_IRQ1P (1u << JZ_CORESTS_IRQ1P_SHIFT)
|
||||||
|
#define JZ_CORESTS_IRQ0P_SHIFT 8
|
||||||
|
#define JZ_CORESTS_IRQ0P (1u << JZ_CORESTS_IRQ0P_SHIFT)
|
||||||
|
#define JZ_CORESTS_MIRQ1P_SHIFT 1
|
||||||
|
#define JZ_CORESTS_MIRQ1P (1u << JZ_CORESTS_MIRQ1P_SHIFT)
|
||||||
|
#define JZ_CORESTS_MIRQ0P_SHIFT 0
|
||||||
|
#define JZ_CORESTS_MIRQ0P (1u << JZ_CORESTS_MIRQ0P_SHIFT)
|
||||||
|
|
||||||
|
/* Reset entry and IRQ mask */
|
||||||
|
#define JZ_REIM_ENTRY_SHIFT 16
|
||||||
|
#define JZ_REIM_ENTRY_WIDTH 16
|
||||||
|
#define JZ_REIM_ENTRY_MASK (0xFFFFu << JZ_REIM_ENTRY_SHIFT)
|
||||||
|
#define JZ_REIM_IRQ1M_SHIFT 9
|
||||||
|
#define JZ_REIM_IRQ1M (1u << JZ_REIM_IRQ1M_SHIFT)
|
||||||
|
#define JZ_REIM_IRQ0M_SHIFT 8
|
||||||
|
#define JZ_REIM_IRQ0M (1u << JZ_REIM_IRQ0M_SHIFT)
|
||||||
|
#define JZ_REIM_MIRQ1M_SHIFT 1
|
||||||
|
#define JZ_REIM_MIRQ1M (1u << JZ_REIM_MIRQ1M_SHIFT)
|
||||||
|
#define JZ_REIM_MIRQ0M_SHIFT 0
|
||||||
|
#define JZ_REIM_MIRQ0M (1u << JZ_REIM_MIRQ0M_SHIFT)
|
||||||
|
|
||||||
|
#endif /* JZ4780_CPUREGS_H */
|
124
sys/mips/ingenic/jz4780_dme.c
Normal file
124
sys/mips/ingenic/jz4780_dme.c
Normal file
@ -0,0 +1,124 @@
|
|||||||
|
/*-
|
||||||
|
* Copyright 2015 Alexander Kabaev <kan@FreeBSD.org>
|
||||||
|
* All rights reserved.
|
||||||
|
*
|
||||||
|
* Redistribution and use in source and binary forms, with or without
|
||||||
|
* modification, are permitted provided that the following conditions
|
||||||
|
* are met:
|
||||||
|
* 1. Redistributions of source code must retain the above copyright
|
||||||
|
* notice, this list of conditions and the following disclaimer.
|
||||||
|
* 2. Redistributions in binary form must reproduce the above copyright
|
||||||
|
* notice, this list of conditions and the following disclaimer in the
|
||||||
|
* documentation and/or other materials provided with the distribution.
|
||||||
|
*
|
||||||
|
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
|
||||||
|
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||||
|
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
||||||
|
* ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
|
||||||
|
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
|
||||||
|
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
|
||||||
|
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
|
||||||
|
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
|
||||||
|
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
|
||||||
|
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
|
||||||
|
* SUCH DAMAGE.
|
||||||
|
*/
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Ingenic JZ4780 NAND and External Memory Controller (NEMC) driver.
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include <sys/cdefs.h>
|
||||||
|
__FBSDID("$FreeBSD$");
|
||||||
|
|
||||||
|
#include <sys/param.h>
|
||||||
|
#include <sys/systm.h>
|
||||||
|
#include <sys/conf.h>
|
||||||
|
#include <sys/bus.h>
|
||||||
|
#include <sys/kernel.h>
|
||||||
|
#include <sys/module.h>
|
||||||
|
#include <sys/lock.h>
|
||||||
|
#include <sys/mutex.h>
|
||||||
|
#include <sys/resource.h>
|
||||||
|
#include <sys/rman.h>
|
||||||
|
|
||||||
|
#include <machine/bus.h>
|
||||||
|
|
||||||
|
#include <dev/fdt/fdt_common.h>
|
||||||
|
#include <dev/ofw/ofw_bus.h>
|
||||||
|
#include <dev/ofw/ofw_bus_subr.h>
|
||||||
|
|
||||||
|
struct jz4780_dme_softc {
|
||||||
|
device_t dev;
|
||||||
|
struct resource *res[2];
|
||||||
|
};
|
||||||
|
|
||||||
|
static struct resource_spec jz4780_dme_spec[] = {
|
||||||
|
{ SYS_RES_MEMORY, 0, RF_ACTIVE },
|
||||||
|
{ SYS_RES_MEMORY, 1, RF_ACTIVE },
|
||||||
|
{ -1, 0 }
|
||||||
|
};
|
||||||
|
|
||||||
|
static int jz4780_dme_probe(device_t dev);
|
||||||
|
static int jz4780_dme_attach(device_t dev);
|
||||||
|
static int jz4780_dme_detach(device_t dev);
|
||||||
|
|
||||||
|
static int
|
||||||
|
jz4780_dme_probe(device_t dev)
|
||||||
|
{
|
||||||
|
|
||||||
|
if (!ofw_bus_status_okay(dev))
|
||||||
|
return (ENXIO);
|
||||||
|
|
||||||
|
if (!ofw_bus_is_compatible(dev, "davicom,dm9000"))
|
||||||
|
return (ENXIO);
|
||||||
|
|
||||||
|
device_set_desc(dev, "Davicom DM9000C 10/100BaseTX");
|
||||||
|
|
||||||
|
return (BUS_PROBE_DEFAULT);
|
||||||
|
}
|
||||||
|
|
||||||
|
static int
|
||||||
|
jz4780_dme_attach(device_t dev)
|
||||||
|
{
|
||||||
|
struct jz4780_dme_softc *sc = device_get_softc(dev);
|
||||||
|
|
||||||
|
sc->dev = dev;
|
||||||
|
|
||||||
|
if (bus_alloc_resources(dev, jz4780_dme_spec, sc->res)) {
|
||||||
|
device_printf(dev, "could not allocate resources for device\n");
|
||||||
|
return (ENXIO);
|
||||||
|
}
|
||||||
|
|
||||||
|
return (0);
|
||||||
|
}
|
||||||
|
|
||||||
|
static int
|
||||||
|
jz4780_dme_detach(device_t dev)
|
||||||
|
{
|
||||||
|
struct jz4780_dme_softc *sc = device_get_softc(dev);
|
||||||
|
|
||||||
|
bus_release_resources(dev, jz4780_dme_spec, sc->res);
|
||||||
|
return (0);
|
||||||
|
}
|
||||||
|
|
||||||
|
static device_method_t jz4780_dme_methods[] = {
|
||||||
|
/* Device interface */
|
||||||
|
DEVMETHOD(device_probe, jz4780_dme_probe),
|
||||||
|
DEVMETHOD(device_attach, jz4780_dme_attach),
|
||||||
|
DEVMETHOD(device_detach, jz4780_dme_detach),
|
||||||
|
|
||||||
|
DEVMETHOD_END
|
||||||
|
};
|
||||||
|
|
||||||
|
static driver_t jz4780_dme_driver = {
|
||||||
|
"dme",
|
||||||
|
jz4780_dme_methods,
|
||||||
|
sizeof(struct jz4780_dme_softc),
|
||||||
|
};
|
||||||
|
|
||||||
|
static devclass_t jz4780_dme_devclass;
|
||||||
|
|
||||||
|
DRIVER_MODULE(jz4780_dme, simplebus, jz4780_dme_driver,
|
||||||
|
jz4780_dme_devclass, 0, 0);
|
202
sys/mips/ingenic/jz4780_dwc_fdt.c
Normal file
202
sys/mips/ingenic/jz4780_dwc_fdt.c
Normal file
@ -0,0 +1,202 @@
|
|||||||
|
/*
|
||||||
|
* Copyright 2015 Alexander Kabaev <kan@FreeBSD.org>.
|
||||||
|
* All rights reserved.
|
||||||
|
*
|
||||||
|
* Redistribution and use in source and binary forms, with or without
|
||||||
|
* modification, are permitted provided that the following conditions are
|
||||||
|
* met:
|
||||||
|
*
|
||||||
|
* 1. Redistributions of source code must retain the above copyright
|
||||||
|
* notice, this list of conditions and the following disclaimer.
|
||||||
|
* 2. Redistributions in binary form must reproduce the above copyright
|
||||||
|
* notice, this list of conditions and the following disclaimer in the
|
||||||
|
* documentation and/or other materials provided with the distribution.
|
||||||
|
*
|
||||||
|
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
|
||||||
|
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||||
|
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
|
||||||
|
* PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE
|
||||||
|
* LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
|
||||||
|
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
|
||||||
|
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
|
||||||
|
* BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
|
||||||
|
* WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
|
||||||
|
* OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
|
||||||
|
* ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include <sys/cdefs.h>
|
||||||
|
__FBSDID("$FreeBSD$");
|
||||||
|
|
||||||
|
#include <sys/param.h>
|
||||||
|
#include <sys/kernel.h>
|
||||||
|
#include <sys/bus.h>
|
||||||
|
#include <sys/callout.h>
|
||||||
|
#include <sys/condvar.h>
|
||||||
|
#include <sys/module.h>
|
||||||
|
|
||||||
|
#include <dev/extres/clk/clk.h>
|
||||||
|
|
||||||
|
#include <dev/ofw/ofw_bus_subr.h>
|
||||||
|
|
||||||
|
#include <dev/usb/usb.h>
|
||||||
|
#include <dev/usb/usbdi.h>
|
||||||
|
|
||||||
|
#include <dev/usb/usb_busdma.h>
|
||||||
|
#include <dev/usb/usb_process.h>
|
||||||
|
|
||||||
|
#include <dev/usb/usb_controller.h>
|
||||||
|
#include <dev/usb/usb_bus.h>
|
||||||
|
|
||||||
|
#include <dev/usb/controller/dwc_otg.h>
|
||||||
|
#include <dev/usb/controller/dwc_otg_fdt.h>
|
||||||
|
|
||||||
|
#include <mips/ingenic/jz4780_clock.h>
|
||||||
|
#include <mips/ingenic/jz4780_regs.h>
|
||||||
|
|
||||||
|
static device_probe_t jz4780_dwc_otg_probe;
|
||||||
|
static device_attach_t jz4780_dwc_otg_attach;
|
||||||
|
static device_detach_t jz4780_dwc_otg_detach;
|
||||||
|
|
||||||
|
struct jz4780_dwc_otg_softc {
|
||||||
|
struct dwc_otg_fdt_softc base; /* storage for DWC OTG code */
|
||||||
|
clk_t phy_clk;
|
||||||
|
clk_t otg_clk;
|
||||||
|
};
|
||||||
|
|
||||||
|
static int
|
||||||
|
jz4780_dwc_otg_clk_enable(device_t dev)
|
||||||
|
{
|
||||||
|
struct jz4780_dwc_otg_softc *sc;
|
||||||
|
int err;
|
||||||
|
|
||||||
|
sc = device_get_softc(dev);
|
||||||
|
|
||||||
|
/* Configure and enable phy clock */
|
||||||
|
err = clk_get_by_ofw_name(dev, 0, "otg_phy", &sc->phy_clk);
|
||||||
|
if (err != 0) {
|
||||||
|
device_printf(dev, "unable to lookup %s clock\n", "otg_phy");
|
||||||
|
return (err);
|
||||||
|
}
|
||||||
|
err = clk_set_freq(sc->phy_clk, 48000000, 0);
|
||||||
|
if (err != 0) {
|
||||||
|
device_printf(dev, "unable to set %s clock to 48 kHZ\n",
|
||||||
|
"otg_phy");
|
||||||
|
return (err);
|
||||||
|
}
|
||||||
|
err = clk_enable(sc->phy_clk);
|
||||||
|
if (err != 0) {
|
||||||
|
device_printf(dev, "unable to enable %s clock\n", "otg_phy");
|
||||||
|
return (err);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Configure and enable otg1 clock */
|
||||||
|
err = clk_get_by_ofw_name(dev, 0, "otg1", &sc->otg_clk);
|
||||||
|
if (err != 0) {
|
||||||
|
device_printf(dev, "unable to lookup %s clock\n", "otg1");
|
||||||
|
return (err);
|
||||||
|
}
|
||||||
|
err = clk_enable(sc->phy_clk);
|
||||||
|
if (err != 0) {
|
||||||
|
device_printf(dev, "unable to enable %s clock\n", "otg1");
|
||||||
|
return (err);
|
||||||
|
}
|
||||||
|
|
||||||
|
return (0);
|
||||||
|
}
|
||||||
|
|
||||||
|
static int
|
||||||
|
jz4780_dwc_otg_probe(device_t dev)
|
||||||
|
{
|
||||||
|
|
||||||
|
if (!ofw_bus_status_okay(dev))
|
||||||
|
return (ENXIO);
|
||||||
|
|
||||||
|
if (!ofw_bus_is_compatible(dev, "ingenic,jz4780-otg"))
|
||||||
|
return (ENXIO);
|
||||||
|
|
||||||
|
device_set_desc(dev, "DWC OTG 2.0 integrated USB controller (jz4780)");
|
||||||
|
|
||||||
|
return (BUS_PROBE_VENDOR);
|
||||||
|
}
|
||||||
|
|
||||||
|
static int
|
||||||
|
jz4780_dwc_otg_attach(device_t dev)
|
||||||
|
{
|
||||||
|
struct jz4780_dwc_otg_softc *sc;
|
||||||
|
struct resource *res;
|
||||||
|
int err, rid;
|
||||||
|
|
||||||
|
sc = device_get_softc(dev);
|
||||||
|
|
||||||
|
err = jz4780_dwc_otg_clk_enable(dev);
|
||||||
|
if (err != 0)
|
||||||
|
goto fail;
|
||||||
|
|
||||||
|
err = jz4780_otg_enable();
|
||||||
|
if (err != 0) {
|
||||||
|
device_printf(dev, "CGU failed to enable OTG\n");
|
||||||
|
goto fail;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Voodoo: Switch off VBUS overcurrent detection in OTG PHY */
|
||||||
|
res = bus_alloc_resource_any(dev, SYS_RES_MEMORY, &rid, RF_ACTIVE);
|
||||||
|
if (res != NULL) {
|
||||||
|
uint32_t reg;
|
||||||
|
|
||||||
|
reg = bus_read_4(res, JZ_DWC2_GUSBCFG);
|
||||||
|
reg |= 0xc;
|
||||||
|
bus_write_4(res, JZ_DWC2_GUSBCFG, reg);
|
||||||
|
bus_release_resource(dev, SYS_RES_MEMORY, rid, res);
|
||||||
|
}
|
||||||
|
|
||||||
|
sc->base.sc_otg.sc_phy_type = DWC_OTG_PHY_UTMI;
|
||||||
|
sc->base.sc_otg.sc_phy_bits = 16;
|
||||||
|
|
||||||
|
err = dwc_otg_attach(dev);
|
||||||
|
if (err != 0)
|
||||||
|
goto fail;
|
||||||
|
|
||||||
|
return (0);
|
||||||
|
fail:
|
||||||
|
if (sc->otg_clk)
|
||||||
|
clk_release(sc->otg_clk);
|
||||||
|
if (sc->phy_clk)
|
||||||
|
clk_release(sc->phy_clk);
|
||||||
|
return (err);
|
||||||
|
}
|
||||||
|
|
||||||
|
static int
|
||||||
|
jz4780_dwc_otg_detach(device_t dev)
|
||||||
|
{
|
||||||
|
struct jz4780_dwc_otg_softc *sc;
|
||||||
|
int err;
|
||||||
|
|
||||||
|
err = dwc_otg_detach(dev);
|
||||||
|
if (err != 0)
|
||||||
|
return (err);
|
||||||
|
|
||||||
|
sc = device_get_softc(dev);
|
||||||
|
if (sc->otg_clk)
|
||||||
|
clk_release(sc->otg_clk);
|
||||||
|
if (sc->phy_clk)
|
||||||
|
clk_release(sc->phy_clk);
|
||||||
|
return (0);
|
||||||
|
}
|
||||||
|
|
||||||
|
static device_method_t jz4780_dwc_otg_methods[] = {
|
||||||
|
/* bus interface */
|
||||||
|
DEVMETHOD(device_probe, jz4780_dwc_otg_probe),
|
||||||
|
DEVMETHOD(device_attach, jz4780_dwc_otg_attach),
|
||||||
|
DEVMETHOD(device_detach, jz4780_dwc_otg_detach),
|
||||||
|
|
||||||
|
DEVMETHOD_END
|
||||||
|
};
|
||||||
|
|
||||||
|
static devclass_t jz4780_dwc_otg_devclass;
|
||||||
|
|
||||||
|
DEFINE_CLASS_1(jzotg, jz4780_dwc_otg_driver, jz4780_dwc_otg_methods,
|
||||||
|
sizeof(struct jz4780_dwc_otg_softc), dwc_otg_driver);
|
||||||
|
DRIVER_MODULE(jzotg, simplebus, jz4780_dwc_otg_driver,
|
||||||
|
jz4780_dwc_otg_devclass, 0, 0);
|
||||||
|
MODULE_DEPEND(jzotg, usb, 1, 1, 1);
|
213
sys/mips/ingenic/jz4780_efuse.c
Normal file
213
sys/mips/ingenic/jz4780_efuse.c
Normal file
@ -0,0 +1,213 @@
|
|||||||
|
/*-
|
||||||
|
* Copyright (c) 2015 Alexander Kabaev <kan@freebsd.org>
|
||||||
|
* All rights reserved.
|
||||||
|
*
|
||||||
|
* Redistribution and use in source and binary forms, with or without
|
||||||
|
* modification, are permitted provided that the following conditions
|
||||||
|
* are met:
|
||||||
|
* 1. Redistributions of source code must retain the above copyright
|
||||||
|
* notice, this list of conditions and the following disclaimer.
|
||||||
|
* 2. Redistributions in binary form must reproduce the above copyright
|
||||||
|
* notice, this list of conditions and the following disclaimer in the
|
||||||
|
* documentation and/or other materials provided with the distribution.
|
||||||
|
*
|
||||||
|
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
|
||||||
|
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||||
|
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
||||||
|
* ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
|
||||||
|
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
|
||||||
|
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
|
||||||
|
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
|
||||||
|
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
|
||||||
|
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
|
||||||
|
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
|
||||||
|
* SUCH DAMAGE.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include <sys/cdefs.h>
|
||||||
|
__FBSDID("$FreeBSD$");
|
||||||
|
|
||||||
|
#include <sys/param.h>
|
||||||
|
#include <sys/systm.h>
|
||||||
|
#include <sys/bus.h>
|
||||||
|
#include <sys/clock.h>
|
||||||
|
#include <sys/kernel.h>
|
||||||
|
#include <sys/limits.h>
|
||||||
|
#include <sys/lock.h>
|
||||||
|
#include <sys/mutex.h>
|
||||||
|
#include <sys/module.h>
|
||||||
|
#include <sys/resource.h>
|
||||||
|
|
||||||
|
#include <machine/bus.h>
|
||||||
|
#include <machine/resource.h>
|
||||||
|
|
||||||
|
#include <dev/fdt/fdt_common.h>
|
||||||
|
#include <dev/ofw/ofw_bus.h>
|
||||||
|
#include <dev/ofw/ofw_bus_subr.h>
|
||||||
|
|
||||||
|
#include <mips/ingenic/jz4780_regs.h>
|
||||||
|
|
||||||
|
static struct ofw_compat_data compat_data[] = {
|
||||||
|
{"ingenic,jz4780-efuse", 1},
|
||||||
|
{NULL, 0}
|
||||||
|
};
|
||||||
|
|
||||||
|
struct jz4780_efuse_data {
|
||||||
|
uint32_t serial_num;
|
||||||
|
uint32_t date;
|
||||||
|
uint8_t nanufacturer[2];
|
||||||
|
uint8_t macaddr[6];
|
||||||
|
} __packed;
|
||||||
|
|
||||||
|
static struct resource_spec jz4780_efuse_spec[] = {
|
||||||
|
{ SYS_RES_MEMORY, 0, RF_ACTIVE },
|
||||||
|
{ -1, 0 }
|
||||||
|
};
|
||||||
|
|
||||||
|
struct jz4780_efuse_softc {
|
||||||
|
device_t dev;
|
||||||
|
struct resource *res[1];
|
||||||
|
struct jz4780_efuse_data data;
|
||||||
|
};
|
||||||
|
|
||||||
|
#define CSR_WRITE_4(sc, reg, val) \
|
||||||
|
bus_write_4((sc)->res[0], (reg), (val))
|
||||||
|
#define CSR_READ_4(sc, reg) \
|
||||||
|
bus_read_4((sc)->res[0], (reg))
|
||||||
|
|
||||||
|
#define JZ_EFUSE_BANK_SIZE (4096 / 8) /* Bank size is 4096 bits */
|
||||||
|
|
||||||
|
static int
|
||||||
|
jz4780_efuse_probe(device_t dev)
|
||||||
|
{
|
||||||
|
if (!ofw_bus_status_okay(dev))
|
||||||
|
return (ENXIO);
|
||||||
|
|
||||||
|
if (ofw_bus_search_compatible(dev, compat_data)->ocd_data == 0)
|
||||||
|
return (ENXIO);
|
||||||
|
|
||||||
|
return (BUS_PROBE_DEFAULT);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
jz4780_efuse_read_chunk(struct jz4780_efuse_softc *sc, int addr, uint8_t *buf, int len)
|
||||||
|
{
|
||||||
|
uint32_t abuf;
|
||||||
|
int i, count;
|
||||||
|
|
||||||
|
/* Setup to read proper bank */
|
||||||
|
CSR_WRITE_4(sc, JZ_EFUCTRL, JZ_EFUSE_READ |
|
||||||
|
(addr < JZ_EFUSE_BANK_SIZE ? 0: JZ_EFUSE_BANK) |
|
||||||
|
(addr << JZ_EFUSE_ADDR_SHIFT) |
|
||||||
|
((len - 1) << JZ_EFUSE_SIZE_SHIFT));
|
||||||
|
/* Wait for read to complete */
|
||||||
|
while ((CSR_READ_4(sc, JZ_EFUSTATE) & JZ_EFUSE_RD_DONE) == 0)
|
||||||
|
DELAY(1000);
|
||||||
|
|
||||||
|
/* Round to 4 bytes for the simple loop below */
|
||||||
|
count = len & ~3;
|
||||||
|
|
||||||
|
for (i = 0; i < count; i += 4) {
|
||||||
|
abuf = CSR_READ_4(sc, JZ_EFUDATA0 + i);
|
||||||
|
memcpy(buf, &abuf, 4);
|
||||||
|
buf += 4;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Read partial word and assign it byte-by-byte */
|
||||||
|
if (i < len) {
|
||||||
|
abuf = CSR_READ_4(sc, JZ_EFUDATA0 + i);
|
||||||
|
for (/* none */; i < len; i++) {
|
||||||
|
buf[i] = abuf & 0xff;
|
||||||
|
abuf >>= 8;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
jz4780_efuse_read(struct jz4780_efuse_softc *sc, int addr, void *buf, int len)
|
||||||
|
{
|
||||||
|
int chunk;
|
||||||
|
|
||||||
|
while (len > 0) {
|
||||||
|
chunk = (len > 32) ? 32 : len;
|
||||||
|
jz4780_efuse_read_chunk(sc, addr, buf, chunk);
|
||||||
|
len -= chunk;
|
||||||
|
buf = (void *)((uintptr_t)buf + chunk);
|
||||||
|
addr += chunk;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
jz4780_efuse_update_kenv(struct jz4780_efuse_softc *sc)
|
||||||
|
{
|
||||||
|
char macstr[sizeof("xx:xx:xx:xx:xx:xx")];
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Update hint in kernel env only if none is available yet.
|
||||||
|
* It is quite possible one was set by command line already.
|
||||||
|
*/
|
||||||
|
if (kern_getenv("hint.dme.0.macaddr") == NULL) {
|
||||||
|
snprintf(macstr, sizeof(macstr), "%6D",
|
||||||
|
sc->data.macaddr, ":");
|
||||||
|
kern_setenv("hint.dme.0.macaddr", macstr);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static int
|
||||||
|
jz4780_efuse_attach(device_t dev)
|
||||||
|
{
|
||||||
|
struct jz4780_efuse_softc *sc;
|
||||||
|
|
||||||
|
sc = device_get_softc(dev);
|
||||||
|
sc->dev = dev;
|
||||||
|
|
||||||
|
if (bus_alloc_resources(dev, jz4780_efuse_spec, sc->res)) {
|
||||||
|
device_printf(dev, "could not allocate resources for device\n");
|
||||||
|
return (ENXIO);
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Default RD_STROBE to 4 h2clk cycles, should already be set to 4 by reset
|
||||||
|
* but configure it anyway.
|
||||||
|
*/
|
||||||
|
CSR_WRITE_4(sc, JZ_EFUCFG, 0x00040000);
|
||||||
|
|
||||||
|
/* Read user-id segment */
|
||||||
|
jz4780_efuse_read(sc, 0x18, &sc->data, sizeof(sc->data));
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Set resource hints for the dme device to discover its
|
||||||
|
* MAC address, if not set already.
|
||||||
|
*/
|
||||||
|
jz4780_efuse_update_kenv(sc);
|
||||||
|
|
||||||
|
/* Resource conflicts with NEMC, release early */
|
||||||
|
bus_release_resources(dev, jz4780_efuse_spec, sc->res);
|
||||||
|
return (0);
|
||||||
|
}
|
||||||
|
|
||||||
|
static int
|
||||||
|
jz4780_efuse_detach(device_t dev)
|
||||||
|
{
|
||||||
|
|
||||||
|
return (0);
|
||||||
|
}
|
||||||
|
|
||||||
|
static device_method_t jz4780_efuse_methods[] = {
|
||||||
|
/* Device interface */
|
||||||
|
DEVMETHOD(device_probe, jz4780_efuse_probe),
|
||||||
|
DEVMETHOD(device_attach, jz4780_efuse_attach),
|
||||||
|
DEVMETHOD(device_detach, jz4780_efuse_detach),
|
||||||
|
|
||||||
|
DEVMETHOD_END
|
||||||
|
};
|
||||||
|
|
||||||
|
static driver_t jz4780_efuse_driver = {
|
||||||
|
"efuse",
|
||||||
|
jz4780_efuse_methods,
|
||||||
|
sizeof(struct jz4780_efuse_softc),
|
||||||
|
};
|
||||||
|
|
||||||
|
static devclass_t jz4780_efuse_devclass;
|
||||||
|
EARLY_DRIVER_MODULE(jz4780_efuse, simplebus, jz4780_efuse_driver,
|
||||||
|
jz4780_efuse_devclass, 0, 0, BUS_PASS_TIMER);
|
345
sys/mips/ingenic/jz4780_ehci.c
Normal file
345
sys/mips/ingenic/jz4780_ehci.c
Normal file
@ -0,0 +1,345 @@
|
|||||||
|
/*-
|
||||||
|
* Copyright (c) 2015 Oleksandr Tymoshenko <gonzo@freebsd.org>.
|
||||||
|
* All rights reserved.
|
||||||
|
*
|
||||||
|
* Redistribution and use in source and binary forms, with or without
|
||||||
|
* modification, are permitted provided that the following conditions
|
||||||
|
* are met:
|
||||||
|
* 1. Redistributions of source code must retain the above copyright
|
||||||
|
* notice, this list of conditions and the following disclaimer.
|
||||||
|
* 2. Redistributions in binary form must reproduce the above copyright
|
||||||
|
* notice, this list of conditions and the following disclaimer in the
|
||||||
|
* documentation and/or other materials provided with the distribution.
|
||||||
|
*
|
||||||
|
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
|
||||||
|
* IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
|
||||||
|
* OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
|
||||||
|
* IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
|
||||||
|
* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
|
||||||
|
* NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
||||||
|
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
||||||
|
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||||
|
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
|
||||||
|
* THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||||
|
*/
|
||||||
|
|
||||||
|
/*
|
||||||
|
* JZ4780 attachment driver for the USB Enhanced Host Controller.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include <sys/cdefs.h>
|
||||||
|
__FBSDID("$FreeBSD$");
|
||||||
|
|
||||||
|
#include "opt_bus.h"
|
||||||
|
|
||||||
|
#include <sys/param.h>
|
||||||
|
#include <sys/systm.h>
|
||||||
|
#include <sys/bus.h>
|
||||||
|
#include <sys/rman.h>
|
||||||
|
#include <sys/condvar.h>
|
||||||
|
#include <sys/kernel.h>
|
||||||
|
#include <sys/module.h>
|
||||||
|
#include <sys/gpio.h>
|
||||||
|
|
||||||
|
#include <dev/extres/clk/clk.h>
|
||||||
|
|
||||||
|
#include <dev/usb/usb.h>
|
||||||
|
#include <dev/usb/usbdi.h>
|
||||||
|
|
||||||
|
#include <dev/usb/usb_core.h>
|
||||||
|
#include <dev/usb/usb_busdma.h>
|
||||||
|
#include <dev/usb/usb_process.h>
|
||||||
|
#include <dev/usb/usb_util.h>
|
||||||
|
|
||||||
|
#include <dev/usb/usb_controller.h>
|
||||||
|
#include <dev/usb/usb_bus.h>
|
||||||
|
#include <dev/usb/controller/ehci.h>
|
||||||
|
#include <dev/usb/controller/ehcireg.h>
|
||||||
|
|
||||||
|
#include <dev/ofw/ofw_bus.h>
|
||||||
|
#include <dev/ofw/ofw_bus_subr.h>
|
||||||
|
|
||||||
|
#include <dev/gpio/gpiobusvar.h>
|
||||||
|
|
||||||
|
#include <mips/ingenic/jz4780_clock.h>
|
||||||
|
#include <mips/ingenic/jz4780_regs.h>
|
||||||
|
|
||||||
|
#define EHCI_HC_DEVSTR "Ingenic JZ4780 EHCI"
|
||||||
|
|
||||||
|
struct jz4780_ehci_softc {
|
||||||
|
ehci_softc_t base; /* storage for EHCI code */
|
||||||
|
clk_t clk;
|
||||||
|
struct gpiobus_pin *gpio_vbus;
|
||||||
|
};
|
||||||
|
|
||||||
|
static device_probe_t jz4780_ehci_probe;
|
||||||
|
static device_attach_t jz4780_ehci_attach;
|
||||||
|
static device_detach_t jz4780_ehci_detach;
|
||||||
|
|
||||||
|
static int
|
||||||
|
jz4780_ehci_vbus_gpio_enable(device_t dev)
|
||||||
|
{
|
||||||
|
struct gpiobus_pin *gpio_vbus;
|
||||||
|
struct jz4780_ehci_softc *sc;
|
||||||
|
int err;
|
||||||
|
|
||||||
|
sc = device_get_softc(dev);
|
||||||
|
|
||||||
|
err = ofw_gpiobus_parse_gpios(dev, "ingenic,vbus-gpio", &gpio_vbus);
|
||||||
|
/*
|
||||||
|
* The pin can ne already mapped by other device. Optimistically
|
||||||
|
* surge ahead.
|
||||||
|
*/
|
||||||
|
if (err <= 0)
|
||||||
|
return (0);
|
||||||
|
|
||||||
|
sc->gpio_vbus = gpio_vbus;
|
||||||
|
if (err > 1) {
|
||||||
|
device_printf(dev, "too many vbus gpios\n");
|
||||||
|
return (ENXIO);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (sc->gpio_vbus != NULL) {
|
||||||
|
err = GPIO_PIN_SETFLAGS(sc->gpio_vbus->dev, sc->gpio_vbus->pin,
|
||||||
|
GPIO_PIN_OUTPUT);
|
||||||
|
if (err != 0) {
|
||||||
|
device_printf(dev, "Cannot configure GPIO pin %d on %s\n",
|
||||||
|
sc->gpio_vbus->pin, device_get_nameunit(sc->gpio_vbus->dev));
|
||||||
|
return (err);
|
||||||
|
}
|
||||||
|
|
||||||
|
err = GPIO_PIN_SET(sc->gpio_vbus->dev, sc->gpio_vbus->pin, 1);
|
||||||
|
if (err != 0) {
|
||||||
|
device_printf(dev, "Cannot configure GPIO pin %d on %s\n",
|
||||||
|
sc->gpio_vbus->pin, device_get_nameunit(sc->gpio_vbus->dev));
|
||||||
|
return (err);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return (0);
|
||||||
|
}
|
||||||
|
|
||||||
|
static int
|
||||||
|
jz4780_ehci_clk_enable(device_t dev)
|
||||||
|
{
|
||||||
|
struct jz4780_ehci_softc *sc;
|
||||||
|
int err;
|
||||||
|
|
||||||
|
sc = device_get_softc(dev);
|
||||||
|
|
||||||
|
err = clk_get_by_ofw_index(dev, 0, 0, &sc->clk);
|
||||||
|
if (err != 0) {
|
||||||
|
device_printf(dev, "unable to lookup device clock\n");
|
||||||
|
return (err);
|
||||||
|
}
|
||||||
|
err = clk_enable(sc->clk);
|
||||||
|
if (err != 0) {
|
||||||
|
device_printf(dev, "unable to enable device clock\n");
|
||||||
|
return (err);
|
||||||
|
}
|
||||||
|
err = clk_set_freq(sc->clk, 48000000, 0);
|
||||||
|
if (err != 0) {
|
||||||
|
device_printf(dev, "unable to set device clock to 48 kHZ\n");
|
||||||
|
return (err);
|
||||||
|
}
|
||||||
|
return (0);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
jz4780_ehci_intr(void *arg)
|
||||||
|
{
|
||||||
|
|
||||||
|
ehci_interrupt(arg);
|
||||||
|
}
|
||||||
|
|
||||||
|
static int
|
||||||
|
jz4780_ehci_probe(device_t dev)
|
||||||
|
{
|
||||||
|
|
||||||
|
if (!ofw_bus_status_okay(dev))
|
||||||
|
return (ENXIO);
|
||||||
|
|
||||||
|
if (!ofw_bus_is_compatible(dev, "ingenic,jz4780-ehci"))
|
||||||
|
return (ENXIO);
|
||||||
|
|
||||||
|
device_set_desc(dev, EHCI_HC_DEVSTR);
|
||||||
|
|
||||||
|
return (BUS_PROBE_DEFAULT);
|
||||||
|
}
|
||||||
|
|
||||||
|
static int
|
||||||
|
jz4780_ehci_attach(device_t dev)
|
||||||
|
{
|
||||||
|
struct jz4780_ehci_softc *isc;
|
||||||
|
ehci_softc_t *sc;
|
||||||
|
int err;
|
||||||
|
int rid;
|
||||||
|
uint32_t reg;
|
||||||
|
|
||||||
|
isc = device_get_softc(dev);
|
||||||
|
sc = &isc->base;
|
||||||
|
|
||||||
|
/* 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;
|
||||||
|
|
||||||
|
/* get all DMA memory */
|
||||||
|
if (usb_bus_mem_alloc_all(&sc->sc_bus,
|
||||||
|
USB_GET_DMA_TAG(dev), &ehci_iterate_hw_softc)) {
|
||||||
|
return (ENOMEM);
|
||||||
|
}
|
||||||
|
|
||||||
|
sc->sc_bus.usbrev = USB_REV_2_0;
|
||||||
|
|
||||||
|
err = jz4780_ehci_vbus_gpio_enable(dev);
|
||||||
|
if (err)
|
||||||
|
goto error;
|
||||||
|
|
||||||
|
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, "Could not map memory\n");
|
||||||
|
goto error;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Craft special resource for bus space ops that handle
|
||||||
|
* byte-alignment of non-word addresses.
|
||||||
|
*/
|
||||||
|
sc->sc_io_tag = rman_get_bustag(sc->sc_io_res);
|
||||||
|
sc->sc_io_hdl = rman_get_bushandle(sc->sc_io_res);
|
||||||
|
sc->sc_io_size = rman_get_size(sc->sc_io_res);
|
||||||
|
|
||||||
|
err = jz4780_ehci_clk_enable(dev);
|
||||||
|
if (err)
|
||||||
|
goto error;
|
||||||
|
|
||||||
|
if (jz4780_ehci_enable() != 0) {
|
||||||
|
device_printf(dev, "CGU failed to enable EHCI\n");
|
||||||
|
err = ENXIO;
|
||||||
|
goto error;
|
||||||
|
}
|
||||||
|
|
||||||
|
EWRITE4(sc, EHCI_USBINTR, 0);
|
||||||
|
|
||||||
|
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) {
|
||||||
|
device_printf(dev, "Could not allocate irq\n");
|
||||||
|
goto error;
|
||||||
|
}
|
||||||
|
sc->sc_bus.bdev = device_add_child(dev, "usbus", -1);
|
||||||
|
if (!sc->sc_bus.bdev) {
|
||||||
|
device_printf(dev, "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, EHCI_HC_DEVSTR);
|
||||||
|
|
||||||
|
sprintf(sc->sc_vendor, "Ingenic");
|
||||||
|
|
||||||
|
err = bus_setup_intr(dev, sc->sc_irq_res, INTR_TYPE_BIO | INTR_MPSAFE,
|
||||||
|
NULL, jz4780_ehci_intr, sc, &sc->sc_intr_hdl);
|
||||||
|
if (err) {
|
||||||
|
device_printf(dev, "Could not setup irq, %d\n", err);
|
||||||
|
sc->sc_intr_hdl = NULL;
|
||||||
|
goto error;
|
||||||
|
}
|
||||||
|
|
||||||
|
err = ehci_init(sc);
|
||||||
|
if (!err) {
|
||||||
|
/* Voodoo: set utmi data bus width on controller to 16 bit */
|
||||||
|
reg = EREAD4(sc, JZ_EHCI_REG_UTMI_BUS);
|
||||||
|
reg |= UTMI_BUS_WIDTH;
|
||||||
|
EWRITE4(sc, JZ_EHCI_REG_UTMI_BUS, reg);
|
||||||
|
|
||||||
|
err = device_probe_and_attach(sc->sc_bus.bdev);
|
||||||
|
}
|
||||||
|
if (err) {
|
||||||
|
device_printf(dev, "USB init failed err=%d\n", err);
|
||||||
|
goto error;
|
||||||
|
}
|
||||||
|
return (0);
|
||||||
|
|
||||||
|
error:
|
||||||
|
jz4780_ehci_detach(dev);
|
||||||
|
return (ENXIO);
|
||||||
|
}
|
||||||
|
|
||||||
|
static int
|
||||||
|
jz4780_ehci_detach(device_t dev)
|
||||||
|
{
|
||||||
|
struct jz4780_ehci_softc *isc;
|
||||||
|
ehci_softc_t *sc;
|
||||||
|
device_t bdev;
|
||||||
|
int err;
|
||||||
|
|
||||||
|
isc = device_get_softc(dev);
|
||||||
|
sc = &isc->base;
|
||||||
|
|
||||||
|
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);
|
||||||
|
|
||||||
|
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)
|
||||||
|
/* XXX or should we panic? */
|
||||||
|
device_printf(dev, "Could not tear down irq, %d\n",
|
||||||
|
err);
|
||||||
|
sc->sc_intr_hdl = NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
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;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (isc->clk)
|
||||||
|
clk_release(isc->clk);
|
||||||
|
|
||||||
|
usb_bus_mem_free_all(&sc->sc_bus, &ehci_iterate_hw_softc);
|
||||||
|
free(isc->gpio_vbus, M_DEVBUF);
|
||||||
|
return (0);
|
||||||
|
}
|
||||||
|
|
||||||
|
static device_method_t ehci_methods[] = {
|
||||||
|
/* Device interface */
|
||||||
|
DEVMETHOD(device_probe, jz4780_ehci_probe),
|
||||||
|
DEVMETHOD(device_attach, jz4780_ehci_attach),
|
||||||
|
DEVMETHOD(device_detach, jz4780_ehci_detach),
|
||||||
|
DEVMETHOD(device_suspend, bus_generic_suspend),
|
||||||
|
DEVMETHOD(device_resume, bus_generic_resume),
|
||||||
|
DEVMETHOD(device_shutdown, bus_generic_shutdown),
|
||||||
|
|
||||||
|
DEVMETHOD_END
|
||||||
|
};
|
||||||
|
|
||||||
|
static driver_t ehci_driver = {
|
||||||
|
.name = "ehci",
|
||||||
|
.methods = ehci_methods,
|
||||||
|
.size = sizeof(struct jz4780_ehci_softc),
|
||||||
|
};
|
||||||
|
|
||||||
|
static devclass_t ehci_devclass;
|
||||||
|
|
||||||
|
DRIVER_MODULE(ehci, simplebus, ehci_driver, ehci_devclass, 0, 0);
|
||||||
|
MODULE_DEPEND(ehci, usb, 1, 1, 1);
|
||||||
|
MODULE_DEPEND(ehci, gpio, 1, 1, 1);
|
830
sys/mips/ingenic/jz4780_gpio.c
Normal file
830
sys/mips/ingenic/jz4780_gpio.c
Normal file
@ -0,0 +1,830 @@
|
|||||||
|
/*-
|
||||||
|
* Copyright 2015 Alexander Kabaev <kan@FreeBSD.org>
|
||||||
|
* All rights reserved.
|
||||||
|
*
|
||||||
|
* Redistribution and use in source and binary forms, with or without
|
||||||
|
* modification, are permitted provided that the following conditions
|
||||||
|
* are met:
|
||||||
|
* 1. Redistributions of source code must retain the above copyright
|
||||||
|
* notice, this list of conditions and the following disclaimer.
|
||||||
|
* 2. Redistributions in binary form must reproduce the above copyright
|
||||||
|
* notice, this list of conditions and the following disclaimer in the
|
||||||
|
* documentation and/or other materials provided with the distribution.
|
||||||
|
*
|
||||||
|
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
|
||||||
|
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||||
|
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
||||||
|
* ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
|
||||||
|
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
|
||||||
|
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
|
||||||
|
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
|
||||||
|
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
|
||||||
|
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
|
||||||
|
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
|
||||||
|
* SUCH DAMAGE.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include <sys/cdefs.h>
|
||||||
|
__FBSDID("$FreeBSD$");
|
||||||
|
|
||||||
|
#include "opt_platform.h"
|
||||||
|
|
||||||
|
#include <sys/param.h>
|
||||||
|
#include <sys/systm.h>
|
||||||
|
#include <sys/conf.h>
|
||||||
|
#include <sys/bus.h>
|
||||||
|
#include <sys/kernel.h>
|
||||||
|
#include <sys/module.h>
|
||||||
|
#include <sys/lock.h>
|
||||||
|
#include <sys/mutex.h>
|
||||||
|
#include <sys/proc.h>
|
||||||
|
#include <sys/resource.h>
|
||||||
|
#include <sys/gpio.h>
|
||||||
|
|
||||||
|
#include <machine/bus.h>
|
||||||
|
#include <machine/intr.h>
|
||||||
|
|
||||||
|
#include <dev/gpio/gpiobusvar.h>
|
||||||
|
|
||||||
|
#include <dev/fdt/fdt_common.h>
|
||||||
|
#include <dev/ofw/ofw_bus.h>
|
||||||
|
#include <dev/ofw/ofw_bus_subr.h>
|
||||||
|
|
||||||
|
#include <mips/ingenic/jz4780_regs.h>
|
||||||
|
#include <gnu/dts/include/dt-bindings/interrupt-controller/irq.h>
|
||||||
|
|
||||||
|
#include "jz4780_gpio_if.h"
|
||||||
|
#include "gpio_if.h"
|
||||||
|
#include "pic_if.h"
|
||||||
|
|
||||||
|
#define JZ4780_GPIO_PINS 32
|
||||||
|
|
||||||
|
enum pin_function {
|
||||||
|
JZ_FUNC_DEV_0,
|
||||||
|
JZ_FUNC_DEV_1,
|
||||||
|
JZ_FUNC_DEV_2,
|
||||||
|
JZ_FUNC_DEV_3,
|
||||||
|
JZ_FUNC_GPIO,
|
||||||
|
JZ_FUNC_INTR,
|
||||||
|
};
|
||||||
|
|
||||||
|
struct jz4780_gpio_pin {
|
||||||
|
struct intr_irqsrc pin_irqsrc;
|
||||||
|
enum intr_trigger intr_trigger;
|
||||||
|
enum intr_polarity intr_polarity;
|
||||||
|
enum pin_function pin_func;
|
||||||
|
uint32_t pin_caps;
|
||||||
|
uint32_t pin_flags;
|
||||||
|
uint32_t pin_num;
|
||||||
|
char pin_name[GPIOMAXNAME];
|
||||||
|
};
|
||||||
|
|
||||||
|
struct jz4780_gpio_softc {
|
||||||
|
device_t dev;
|
||||||
|
device_t busdev;
|
||||||
|
struct resource *res[2];
|
||||||
|
struct mtx mtx;
|
||||||
|
struct jz4780_gpio_pin pins[JZ4780_GPIO_PINS];
|
||||||
|
void *intrhand;
|
||||||
|
};
|
||||||
|
|
||||||
|
static struct resource_spec jz4780_gpio_spec[] = {
|
||||||
|
{ SYS_RES_MEMORY, 0, RF_ACTIVE },
|
||||||
|
{ SYS_RES_IRQ, 0, RF_ACTIVE },
|
||||||
|
{ -1, 0 }
|
||||||
|
};
|
||||||
|
|
||||||
|
static int jz4780_gpio_probe(device_t dev);
|
||||||
|
static int jz4780_gpio_attach(device_t dev);
|
||||||
|
static int jz4780_gpio_detach(device_t dev);
|
||||||
|
static int jz4780_gpio_intr(void *arg);
|
||||||
|
|
||||||
|
#define JZ4780_GPIO_LOCK(sc) mtx_lock_spin(&(sc)->mtx)
|
||||||
|
#define JZ4780_GPIO_UNLOCK(sc) mtx_unlock_spin(&(sc)->mtx)
|
||||||
|
#define JZ4780_GPIO_LOCK_INIT(sc) \
|
||||||
|
mtx_init(&(sc)->mtx, device_get_nameunit((sc)->dev), \
|
||||||
|
"jz4780_gpio", MTX_SPIN)
|
||||||
|
#define JZ4780_GPIO_LOCK_DESTROY(sc) mtx_destroy(&(sc)->mtx);
|
||||||
|
|
||||||
|
#define CSR_WRITE_4(sc, reg, val) bus_write_4((sc)->res[0], (reg), (val))
|
||||||
|
#define CSR_READ_4(sc, reg) bus_read_4((sc)->res[0], (reg))
|
||||||
|
|
||||||
|
static int
|
||||||
|
jz4780_gpio_probe(device_t dev)
|
||||||
|
{
|
||||||
|
phandle_t node;
|
||||||
|
|
||||||
|
if (!ofw_bus_status_okay(dev))
|
||||||
|
return (ENXIO);
|
||||||
|
|
||||||
|
/* We only like particular parent */
|
||||||
|
if (!ofw_bus_is_compatible(device_get_parent(dev),
|
||||||
|
"ingenic,jz4780-pinctrl"))
|
||||||
|
return (ENXIO);
|
||||||
|
|
||||||
|
/* ... and only specific children os that parent */
|
||||||
|
node = ofw_bus_get_node(dev);
|
||||||
|
if (!OF_hasprop(node, "gpio-controller"))
|
||||||
|
return (ENXIO);
|
||||||
|
|
||||||
|
device_set_desc(dev, "Ingenic JZ4780 GPIO Controller");
|
||||||
|
|
||||||
|
return (BUS_PROBE_DEFAULT);
|
||||||
|
}
|
||||||
|
|
||||||
|
static int
|
||||||
|
jz4780_gpio_pin_set_func(struct jz4780_gpio_softc *sc, uint32_t pin,
|
||||||
|
uint32_t func)
|
||||||
|
{
|
||||||
|
uint32_t mask = (1u << pin);
|
||||||
|
|
||||||
|
if (func > (uint32_t)JZ_FUNC_DEV_3)
|
||||||
|
return (EINVAL);
|
||||||
|
|
||||||
|
CSR_WRITE_4(sc, JZ_GPIO_INTC, mask);
|
||||||
|
CSR_WRITE_4(sc, JZ_GPIO_MASKC, mask);
|
||||||
|
if (func & 2)
|
||||||
|
CSR_WRITE_4(sc, JZ_GPIO_PAT1S, mask);
|
||||||
|
else
|
||||||
|
CSR_WRITE_4(sc, JZ_GPIO_PAT1C, mask);
|
||||||
|
if (func & 1)
|
||||||
|
CSR_WRITE_4(sc, JZ_GPIO_PAT0S, mask);
|
||||||
|
else
|
||||||
|
CSR_WRITE_4(sc, JZ_GPIO_PAT0C, mask);
|
||||||
|
|
||||||
|
sc->pins[pin].pin_flags &= ~(GPIO_PIN_INPUT | GPIO_PIN_OUTPUT);
|
||||||
|
sc->pins[pin].pin_func = (enum pin_function)func;
|
||||||
|
return (0);
|
||||||
|
}
|
||||||
|
|
||||||
|
static int
|
||||||
|
jz4780_gpio_pin_set_direction(struct jz4780_gpio_softc *sc,
|
||||||
|
uint32_t pin, uint32_t dir)
|
||||||
|
{
|
||||||
|
uint32_t mask = (1u << pin);
|
||||||
|
|
||||||
|
switch (dir) {
|
||||||
|
case GPIO_PIN_OUTPUT:
|
||||||
|
if (sc->pins[pin].pin_caps & dir)
|
||||||
|
CSR_WRITE_4(sc, JZ_GPIO_PAT1C, mask);
|
||||||
|
else
|
||||||
|
return (EINVAL);
|
||||||
|
break;
|
||||||
|
case GPIO_PIN_INPUT:
|
||||||
|
if (sc->pins[pin].pin_caps & dir)
|
||||||
|
CSR_WRITE_4(sc, JZ_GPIO_PAT1S, mask);
|
||||||
|
else
|
||||||
|
return (EINVAL);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
sc->pins[pin].pin_flags &= ~(GPIO_PIN_INPUT | GPIO_PIN_OUTPUT);
|
||||||
|
sc->pins[pin].pin_flags |= dir;
|
||||||
|
return (0);
|
||||||
|
}
|
||||||
|
|
||||||
|
static int
|
||||||
|
jz4780_gpio_pin_set_bias(struct jz4780_gpio_softc *sc,
|
||||||
|
uint32_t pin, uint32_t bias)
|
||||||
|
{
|
||||||
|
uint32_t mask = (1u << pin);
|
||||||
|
|
||||||
|
switch (bias) {
|
||||||
|
case GPIO_PIN_PULLUP:
|
||||||
|
case GPIO_PIN_PULLDOWN:
|
||||||
|
if (sc->pins[pin].pin_caps & bias)
|
||||||
|
CSR_WRITE_4(sc, JZ_GPIO_DPULLC, mask);
|
||||||
|
else
|
||||||
|
return (EINVAL);
|
||||||
|
break;
|
||||||
|
case 0:
|
||||||
|
CSR_WRITE_4(sc, JZ_GPIO_DPULLS, mask);
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
return (ENOTSUP);
|
||||||
|
}
|
||||||
|
|
||||||
|
sc->pins[pin].pin_flags &= ~(GPIO_PIN_PULLUP | GPIO_PIN_PULLDOWN);
|
||||||
|
sc->pins[pin].pin_flags |= bias;
|
||||||
|
return (0);
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Decode pin configuration using this map
|
||||||
|
*/
|
||||||
|
#if 0
|
||||||
|
INT MASK PAT1 PAT0
|
||||||
|
1 x 0 0 /* intr, level, low */
|
||||||
|
1 x 0 1 /* intr, level, high */
|
||||||
|
1 x 1 0 /* intr, edge, falling */
|
||||||
|
1 x 1 1 /* intr, edge, rising */
|
||||||
|
0 0 0 0 /* function, func 0 */
|
||||||
|
0 0 0 1 /* function, func 1 */
|
||||||
|
0 0 1 0 /* function, func 2 */
|
||||||
|
0 0 1 0 /* function, func 3 */
|
||||||
|
0 1 0 0 /* gpio, output 0 */
|
||||||
|
0 1 0 1 /* gpio, output 1 */
|
||||||
|
0 1 1 x /* gpio, input */
|
||||||
|
#endif
|
||||||
|
|
||||||
|
static void
|
||||||
|
jz4780_gpio_pin_probe(struct jz4780_gpio_softc *sc, uint32_t pin)
|
||||||
|
{
|
||||||
|
uint32_t mask = (1u << pin);
|
||||||
|
uint32_t val;
|
||||||
|
|
||||||
|
/* Clear cached gpio config */
|
||||||
|
sc->pins[pin].pin_flags = 0;
|
||||||
|
|
||||||
|
/* First check if pin is in interrupt mode */
|
||||||
|
val = CSR_READ_4(sc, JZ_GPIO_INT);
|
||||||
|
if (val & mask) {
|
||||||
|
/* Pin is in interrupt mode, decode interrupt triggering mode */
|
||||||
|
val = CSR_READ_4(sc, JZ_GPIO_PAT1);
|
||||||
|
if (val & mask)
|
||||||
|
sc->pins[pin].intr_trigger = INTR_TRIGGER_EDGE;
|
||||||
|
else
|
||||||
|
sc->pins[pin].intr_trigger = INTR_TRIGGER_LEVEL;
|
||||||
|
/* Decode interrupt polarity */
|
||||||
|
val = CSR_READ_4(sc, JZ_GPIO_PAT0);
|
||||||
|
if (val & mask)
|
||||||
|
sc->pins[pin].intr_polarity = INTR_POLARITY_HIGH;
|
||||||
|
else
|
||||||
|
sc->pins[pin].intr_polarity = INTR_POLARITY_LOW;
|
||||||
|
|
||||||
|
sc->pins[pin].pin_func = JZ_FUNC_INTR;
|
||||||
|
sc->pins[pin].pin_flags = 0;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
/* Next check if pin is in gpio mode */
|
||||||
|
val = CSR_READ_4(sc, JZ_GPIO_MASK);
|
||||||
|
if (val & mask) {
|
||||||
|
/* Pin is in gpio mode, decode direction and bias */
|
||||||
|
val = CSR_READ_4(sc, JZ_GPIO_PAT1);
|
||||||
|
if (val & mask)
|
||||||
|
sc->pins[pin].pin_flags |= GPIO_PIN_INPUT;
|
||||||
|
else
|
||||||
|
sc->pins[pin].pin_flags |= GPIO_PIN_OUTPUT;
|
||||||
|
/* Check for bias */
|
||||||
|
val = CSR_READ_4(sc, JZ_GPIO_DPULL);
|
||||||
|
if ((val & mask) == 0)
|
||||||
|
sc->pins[pin].pin_flags |= sc->pins[pin].pin_caps &
|
||||||
|
(GPIO_PIN_PULLUP | GPIO_PIN_PULLDOWN);
|
||||||
|
sc->pins[pin].pin_func = JZ_FUNC_GPIO;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
/* By exclusion, pin is in alternate function mode */
|
||||||
|
val = CSR_READ_4(sc, JZ_GPIO_DPULL);
|
||||||
|
if ((val & mask) == 0)
|
||||||
|
sc->pins[pin].pin_flags = sc->pins[pin].pin_caps &
|
||||||
|
(GPIO_PIN_PULLUP | GPIO_PIN_PULLDOWN);
|
||||||
|
val = ((CSR_READ_4(sc, JZ_GPIO_PAT1) & mask) >> pin) << 1;
|
||||||
|
val = val | ((CSR_READ_4(sc, JZ_GPIO_PAT1) & mask) >> pin);
|
||||||
|
sc->pins[pin].pin_func = (enum pin_function)val;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int
|
||||||
|
jz4780_gpio_register_isrcs(struct jz4780_gpio_softc *sc)
|
||||||
|
{
|
||||||
|
int error;
|
||||||
|
uint32_t irq, i;
|
||||||
|
struct intr_irqsrc *isrc;
|
||||||
|
const char *name;
|
||||||
|
|
||||||
|
name = device_get_nameunit(sc->dev);
|
||||||
|
for (irq = 0; irq < JZ4780_GPIO_PINS; irq++) {
|
||||||
|
isrc = &sc->pins[irq].pin_irqsrc;
|
||||||
|
error = intr_isrc_register(isrc, sc->dev, 0, "%s,%d",
|
||||||
|
name, irq);
|
||||||
|
if (error != 0) {
|
||||||
|
for (i = 0; i < irq; i++)
|
||||||
|
intr_isrc_deregister(&sc->pins[i].pin_irqsrc);
|
||||||
|
device_printf(sc->dev, "%s failed", __func__);
|
||||||
|
return (error);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return (0);
|
||||||
|
}
|
||||||
|
|
||||||
|
static int
|
||||||
|
jz4780_gpio_attach(device_t dev)
|
||||||
|
{
|
||||||
|
struct jz4780_gpio_softc *sc = device_get_softc(dev);
|
||||||
|
phandle_t node;
|
||||||
|
uint32_t i, pd_pins, pu_pins;
|
||||||
|
|
||||||
|
sc->dev = dev;
|
||||||
|
|
||||||
|
if (bus_alloc_resources(dev, jz4780_gpio_spec, sc->res)) {
|
||||||
|
device_printf(dev, "could not allocate resources for device\n");
|
||||||
|
return (ENXIO);
|
||||||
|
}
|
||||||
|
|
||||||
|
JZ4780_GPIO_LOCK_INIT(sc);
|
||||||
|
|
||||||
|
node = ofw_bus_get_node(dev);
|
||||||
|
OF_getencprop(node, "ingenic,pull-ups", &pu_pins, sizeof(pu_pins));
|
||||||
|
OF_getencprop(node, "ingenic,pull-downs", &pd_pins, sizeof(pd_pins));
|
||||||
|
|
||||||
|
for (i = 0; i < JZ4780_GPIO_PINS; i++) {
|
||||||
|
sc->pins[i].pin_num = i;
|
||||||
|
sc->pins[i].pin_caps |= GPIO_PIN_INPUT | GPIO_PIN_OUTPUT;
|
||||||
|
if (pu_pins & (1 << i))
|
||||||
|
sc->pins[i].pin_caps |= GPIO_PIN_PULLUP;
|
||||||
|
if (pd_pins & (1 << i))
|
||||||
|
sc->pins[i].pin_caps |= GPIO_PIN_PULLDOWN;
|
||||||
|
sc->pins[i].intr_polarity = INTR_POLARITY_CONFORM;
|
||||||
|
sc->pins[i].intr_trigger = INTR_TRIGGER_CONFORM;
|
||||||
|
|
||||||
|
snprintf(sc->pins[i].pin_name, GPIOMAXNAME - 1, "gpio%c%d",
|
||||||
|
device_get_unit(dev) + 'a', i);
|
||||||
|
sc->pins[i].pin_name[GPIOMAXNAME - 1] = '\0';
|
||||||
|
|
||||||
|
jz4780_gpio_pin_probe(sc, i);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (jz4780_gpio_register_isrcs(sc) != 0)
|
||||||
|
goto fail;
|
||||||
|
|
||||||
|
if (intr_pic_register(dev, OF_xref_from_node(node)) == NULL) {
|
||||||
|
device_printf(dev, "could not register PIC\n");
|
||||||
|
goto fail;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (bus_setup_intr(dev, sc->res[1], INTR_TYPE_MISC | INTR_MPSAFE,
|
||||||
|
jz4780_gpio_intr, NULL, sc, &sc->intrhand) != 0)
|
||||||
|
goto fail_pic;
|
||||||
|
|
||||||
|
sc->busdev = gpiobus_attach_bus(dev);
|
||||||
|
if (sc->busdev == NULL)
|
||||||
|
goto fail_pic;
|
||||||
|
|
||||||
|
return (0);
|
||||||
|
fail_pic:
|
||||||
|
intr_pic_deregister(dev, OF_xref_from_node(node));
|
||||||
|
fail:
|
||||||
|
if (sc->intrhand != NULL)
|
||||||
|
bus_teardown_intr(dev, sc->res[1], sc->intrhand);
|
||||||
|
bus_release_resources(dev, jz4780_gpio_spec, sc->res);
|
||||||
|
JZ4780_GPIO_LOCK_DESTROY(sc);
|
||||||
|
return (ENXIO);
|
||||||
|
}
|
||||||
|
|
||||||
|
static int
|
||||||
|
jz4780_gpio_detach(device_t dev)
|
||||||
|
{
|
||||||
|
struct jz4780_gpio_softc *sc = device_get_softc(dev);
|
||||||
|
|
||||||
|
bus_release_resources(dev, jz4780_gpio_spec, sc->res);
|
||||||
|
JZ4780_GPIO_LOCK_DESTROY(sc);
|
||||||
|
return (0);
|
||||||
|
}
|
||||||
|
|
||||||
|
static int
|
||||||
|
jz4780_gpio_configure_pin(device_t dev, uint32_t pin, uint32_t func,
|
||||||
|
uint32_t flags)
|
||||||
|
{
|
||||||
|
struct jz4780_gpio_softc *sc;
|
||||||
|
int retval;
|
||||||
|
|
||||||
|
if (pin >= JZ4780_GPIO_PINS)
|
||||||
|
return (EINVAL);
|
||||||
|
|
||||||
|
sc = device_get_softc(dev);
|
||||||
|
JZ4780_GPIO_LOCK(sc);
|
||||||
|
retval = jz4780_gpio_pin_set_func(sc, pin, func);
|
||||||
|
if (retval == 0)
|
||||||
|
retval = jz4780_gpio_pin_set_bias(sc, pin, flags);
|
||||||
|
JZ4780_GPIO_UNLOCK(sc);
|
||||||
|
return (retval);
|
||||||
|
}
|
||||||
|
|
||||||
|
static device_t
|
||||||
|
jz4780_gpio_get_bus(device_t dev)
|
||||||
|
{
|
||||||
|
struct jz4780_gpio_softc *sc;
|
||||||
|
|
||||||
|
sc = device_get_softc(dev);
|
||||||
|
|
||||||
|
return (sc->busdev);
|
||||||
|
}
|
||||||
|
|
||||||
|
static int
|
||||||
|
jz4780_gpio_pin_max(device_t dev, int *maxpin)
|
||||||
|
{
|
||||||
|
|
||||||
|
*maxpin = JZ4780_GPIO_PINS - 1;
|
||||||
|
return (0);
|
||||||
|
}
|
||||||
|
|
||||||
|
static int
|
||||||
|
jz4780_gpio_pin_getcaps(device_t dev, uint32_t pin, uint32_t *caps)
|
||||||
|
{
|
||||||
|
struct jz4780_gpio_softc *sc;
|
||||||
|
|
||||||
|
if (pin >= JZ4780_GPIO_PINS)
|
||||||
|
return (EINVAL);
|
||||||
|
|
||||||
|
sc = device_get_softc(dev);
|
||||||
|
JZ4780_GPIO_LOCK(sc);
|
||||||
|
*caps = sc->pins[pin].pin_caps;
|
||||||
|
JZ4780_GPIO_UNLOCK(sc);
|
||||||
|
|
||||||
|
return (0);
|
||||||
|
}
|
||||||
|
|
||||||
|
static int
|
||||||
|
jz4780_gpio_pin_getflags(device_t dev, uint32_t pin, uint32_t *flags)
|
||||||
|
{
|
||||||
|
struct jz4780_gpio_softc *sc;
|
||||||
|
|
||||||
|
if (pin >= JZ4780_GPIO_PINS)
|
||||||
|
return (EINVAL);
|
||||||
|
|
||||||
|
sc = device_get_softc(dev);
|
||||||
|
JZ4780_GPIO_LOCK(sc);
|
||||||
|
*flags = sc->pins[pin].pin_flags;
|
||||||
|
JZ4780_GPIO_UNLOCK(sc);
|
||||||
|
|
||||||
|
return (0);
|
||||||
|
}
|
||||||
|
|
||||||
|
static int
|
||||||
|
jz4780_gpio_pin_getname(device_t dev, uint32_t pin, char *name)
|
||||||
|
{
|
||||||
|
struct jz4780_gpio_softc *sc;
|
||||||
|
|
||||||
|
if (pin >= JZ4780_GPIO_PINS)
|
||||||
|
return (EINVAL);
|
||||||
|
|
||||||
|
sc = device_get_softc(dev);
|
||||||
|
strncpy(name, sc->pins[pin].pin_name, GPIOMAXNAME - 1);
|
||||||
|
name[GPIOMAXNAME - 1] = '\0';
|
||||||
|
|
||||||
|
return (0);
|
||||||
|
}
|
||||||
|
|
||||||
|
static int
|
||||||
|
jz4780_gpio_pin_setflags(device_t dev, uint32_t pin, uint32_t flags)
|
||||||
|
{
|
||||||
|
struct jz4780_gpio_softc *sc;
|
||||||
|
int retval;
|
||||||
|
|
||||||
|
if (pin >= JZ4780_GPIO_PINS)
|
||||||
|
return (EINVAL);
|
||||||
|
|
||||||
|
sc = device_get_softc(dev);
|
||||||
|
JZ4780_GPIO_LOCK(sc);
|
||||||
|
retval = jz4780_gpio_pin_set_direction(sc, pin,
|
||||||
|
flags & (GPIO_PIN_INPUT | GPIO_PIN_OUTPUT));
|
||||||
|
if (retval == 0)
|
||||||
|
retval = jz4780_gpio_pin_set_bias(sc, pin,
|
||||||
|
flags & (GPIO_PIN_PULLDOWN | GPIO_PIN_PULLUP));
|
||||||
|
JZ4780_GPIO_UNLOCK(sc);
|
||||||
|
|
||||||
|
return (retval);
|
||||||
|
}
|
||||||
|
|
||||||
|
static int
|
||||||
|
jz4780_gpio_pin_set(device_t dev, uint32_t pin, unsigned int value)
|
||||||
|
{
|
||||||
|
struct jz4780_gpio_softc *sc;
|
||||||
|
uint32_t mask;
|
||||||
|
int retval;
|
||||||
|
|
||||||
|
if (pin >= JZ4780_GPIO_PINS)
|
||||||
|
return (EINVAL);
|
||||||
|
|
||||||
|
retval = EINVAL;
|
||||||
|
mask = (1u << pin);
|
||||||
|
sc = device_get_softc(dev);
|
||||||
|
JZ4780_GPIO_LOCK(sc);
|
||||||
|
if (sc->pins[pin].pin_func == JZ_FUNC_GPIO) {
|
||||||
|
CSR_WRITE_4(sc, value ? JZ_GPIO_PAT0S : JZ_GPIO_PAT0C, mask);
|
||||||
|
retval = 0;
|
||||||
|
}
|
||||||
|
JZ4780_GPIO_UNLOCK(sc);
|
||||||
|
|
||||||
|
return (retval);
|
||||||
|
}
|
||||||
|
|
||||||
|
static int
|
||||||
|
jz4780_gpio_pin_get(device_t dev, uint32_t pin, unsigned int *val)
|
||||||
|
{
|
||||||
|
struct jz4780_gpio_softc *sc;
|
||||||
|
uint32_t data, mask;
|
||||||
|
|
||||||
|
if (pin >= JZ4780_GPIO_PINS)
|
||||||
|
return (EINVAL);
|
||||||
|
|
||||||
|
mask = (1u << pin);
|
||||||
|
sc = device_get_softc(dev);
|
||||||
|
JZ4780_GPIO_LOCK(sc);
|
||||||
|
data = CSR_READ_4(sc, JZ_GPIO_PIN);
|
||||||
|
JZ4780_GPIO_UNLOCK(sc);
|
||||||
|
*val = (data & mask) ? 1 : 0;
|
||||||
|
|
||||||
|
return (0);
|
||||||
|
}
|
||||||
|
|
||||||
|
static int
|
||||||
|
jz4780_gpio_pin_toggle(device_t dev, uint32_t pin)
|
||||||
|
{
|
||||||
|
struct jz4780_gpio_softc *sc;
|
||||||
|
uint32_t data, mask;
|
||||||
|
int retval;
|
||||||
|
|
||||||
|
if (pin >= JZ4780_GPIO_PINS)
|
||||||
|
return (EINVAL);
|
||||||
|
|
||||||
|
retval = EINVAL;
|
||||||
|
mask = (1u << pin);
|
||||||
|
sc = device_get_softc(dev);
|
||||||
|
JZ4780_GPIO_LOCK(sc);
|
||||||
|
if (sc->pins[pin].pin_func == JZ_FUNC_GPIO &&
|
||||||
|
sc->pins[pin].pin_flags & GPIO_PIN_OUTPUT) {
|
||||||
|
data = CSR_READ_4(sc, JZ_GPIO_PIN);
|
||||||
|
CSR_WRITE_4(sc, (data & mask) ? JZ_GPIO_PAT0C : JZ_GPIO_PAT0S,
|
||||||
|
mask);
|
||||||
|
retval = 0;
|
||||||
|
}
|
||||||
|
JZ4780_GPIO_UNLOCK(sc);
|
||||||
|
|
||||||
|
return (retval);
|
||||||
|
}
|
||||||
|
|
||||||
|
#ifdef FDT
|
||||||
|
static int
|
||||||
|
jz_gpio_map_intr_fdt(device_t dev, struct intr_map_data *data, u_int *irqp,
|
||||||
|
enum intr_polarity *polp, enum intr_trigger *trigp)
|
||||||
|
{
|
||||||
|
struct jz4780_gpio_softc *sc;
|
||||||
|
struct intr_map_data_fdt *daf;
|
||||||
|
|
||||||
|
sc = device_get_softc(dev);
|
||||||
|
daf = (struct intr_map_data_fdt *)data;
|
||||||
|
|
||||||
|
if (data == NULL || data->type != INTR_MAP_DATA_FDT ||
|
||||||
|
daf->ncells == 0 || daf->ncells > 2)
|
||||||
|
return (EINVAL);
|
||||||
|
|
||||||
|
*irqp = daf->cells[0];
|
||||||
|
if (daf->ncells == 1) {
|
||||||
|
*trigp = INTR_TRIGGER_CONFORM;
|
||||||
|
*polp = INTR_POLARITY_CONFORM;
|
||||||
|
return (0);
|
||||||
|
}
|
||||||
|
|
||||||
|
switch (daf->cells[1])
|
||||||
|
{
|
||||||
|
case IRQ_TYPE_EDGE_RISING:
|
||||||
|
*trigp = INTR_TRIGGER_EDGE;
|
||||||
|
*polp = INTR_POLARITY_HIGH;
|
||||||
|
break;
|
||||||
|
case IRQ_TYPE_EDGE_FALLING:
|
||||||
|
*trigp = INTR_TRIGGER_EDGE;
|
||||||
|
*polp = INTR_POLARITY_LOW;
|
||||||
|
break;
|
||||||
|
case IRQ_TYPE_LEVEL_HIGH:
|
||||||
|
*trigp = INTR_TRIGGER_LEVEL;
|
||||||
|
*polp = INTR_POLARITY_HIGH;
|
||||||
|
break;
|
||||||
|
case IRQ_TYPE_LEVEL_LOW:
|
||||||
|
*trigp = INTR_TRIGGER_LEVEL;
|
||||||
|
*polp = INTR_POLARITY_LOW;
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
device_printf(sc->dev, "unsupported trigger/polarity 0x%2x\n",
|
||||||
|
daf->cells[1]);
|
||||||
|
return (ENOTSUP);
|
||||||
|
}
|
||||||
|
|
||||||
|
return (0);
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
static int
|
||||||
|
jz_gpio_map_intr(device_t dev, struct intr_map_data *data, u_int *irqp,
|
||||||
|
enum intr_polarity *polp, enum intr_trigger *trigp)
|
||||||
|
{
|
||||||
|
struct jz4780_gpio_softc *sc;
|
||||||
|
enum intr_polarity pol;
|
||||||
|
enum intr_trigger trig;
|
||||||
|
u_int irq;
|
||||||
|
|
||||||
|
sc = device_get_softc(dev);
|
||||||
|
switch (data->type) {
|
||||||
|
#ifdef FDT
|
||||||
|
case INTR_MAP_DATA_FDT:
|
||||||
|
if (jz_gpio_map_intr_fdt(dev, data, &irq, &pol, &trig) != 0)
|
||||||
|
return (EINVAL);
|
||||||
|
break;
|
||||||
|
#endif
|
||||||
|
default:
|
||||||
|
return (EINVAL);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (irq >= nitems(sc->pins))
|
||||||
|
return (EINVAL);
|
||||||
|
|
||||||
|
*irqp = irq;
|
||||||
|
if (polp != NULL)
|
||||||
|
*polp = pol;
|
||||||
|
if (trigp != NULL)
|
||||||
|
*trigp = trig;
|
||||||
|
return (0);
|
||||||
|
}
|
||||||
|
|
||||||
|
static int
|
||||||
|
jz4780_gpio_pic_map_intr(device_t dev, struct intr_map_data *data,
|
||||||
|
struct intr_irqsrc **isrcp)
|
||||||
|
{
|
||||||
|
struct jz4780_gpio_softc *sc;
|
||||||
|
int retval;
|
||||||
|
u_int irq;
|
||||||
|
|
||||||
|
retval = jz_gpio_map_intr(dev, data, &irq, NULL, NULL);
|
||||||
|
if (retval == 0) {
|
||||||
|
sc = device_get_softc(dev);
|
||||||
|
*isrcp = &sc->pins[irq].pin_irqsrc;
|
||||||
|
}
|
||||||
|
return (retval);
|
||||||
|
}
|
||||||
|
|
||||||
|
static int
|
||||||
|
jz4780_gpio_pic_setup_intr(device_t dev, struct intr_irqsrc *isrc,
|
||||||
|
struct resource *res, struct intr_map_data *data)
|
||||||
|
{
|
||||||
|
struct jz4780_gpio_softc *sc;
|
||||||
|
struct jz4780_gpio_pin *pin;
|
||||||
|
enum intr_polarity pol;
|
||||||
|
enum intr_trigger trig;
|
||||||
|
uint32_t mask, irq;
|
||||||
|
|
||||||
|
if (data == NULL)
|
||||||
|
return (ENOTSUP);
|
||||||
|
|
||||||
|
/* Get config for resource. */
|
||||||
|
if (jz_gpio_map_intr(dev, data, &irq, &pol, &trig))
|
||||||
|
return (EINVAL);
|
||||||
|
|
||||||
|
pin = __containerof(isrc, struct jz4780_gpio_pin, pin_irqsrc);
|
||||||
|
if (isrc != &pin->pin_irqsrc)
|
||||||
|
return (EINVAL);
|
||||||
|
|
||||||
|
/* Compare config if this is not first setup. */
|
||||||
|
if (isrc->isrc_handlers != 0) {
|
||||||
|
if ((pol != INTR_POLARITY_CONFORM && pol != pin->intr_polarity) ||
|
||||||
|
(trig != INTR_TRIGGER_CONFORM && trig != pin->intr_trigger))
|
||||||
|
return (EINVAL);
|
||||||
|
else
|
||||||
|
return (0);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (pol == INTR_POLARITY_CONFORM)
|
||||||
|
pol = INTR_POLARITY_LOW; /* just pick some */
|
||||||
|
if (trig == INTR_TRIGGER_CONFORM)
|
||||||
|
trig = INTR_TRIGGER_EDGE; /* just pick some */
|
||||||
|
|
||||||
|
sc = device_get_softc(dev);
|
||||||
|
mask = 1u << pin->pin_num;
|
||||||
|
|
||||||
|
JZ4780_GPIO_LOCK(sc);
|
||||||
|
CSR_WRITE_4(sc, JZ_GPIO_MASKS, mask);
|
||||||
|
CSR_WRITE_4(sc, JZ_GPIO_INTS, mask);
|
||||||
|
|
||||||
|
if (trig == INTR_TRIGGER_LEVEL)
|
||||||
|
CSR_WRITE_4(sc, JZ_GPIO_PAT1C, mask);
|
||||||
|
else
|
||||||
|
CSR_WRITE_4(sc, JZ_GPIO_PAT1S, mask);
|
||||||
|
|
||||||
|
if (pol == INTR_POLARITY_LOW)
|
||||||
|
CSR_WRITE_4(sc, JZ_GPIO_PAT0C, mask);
|
||||||
|
else
|
||||||
|
CSR_WRITE_4(sc, JZ_GPIO_PAT0S, mask);
|
||||||
|
|
||||||
|
pin->pin_func = JZ_FUNC_INTR;
|
||||||
|
pin->intr_trigger = trig;
|
||||||
|
pin->intr_polarity = pol;
|
||||||
|
|
||||||
|
CSR_WRITE_4(sc, JZ_GPIO_FLAGC, mask);
|
||||||
|
CSR_WRITE_4(sc, JZ_GPIO_MASKC, mask);
|
||||||
|
JZ4780_GPIO_UNLOCK(sc);
|
||||||
|
return (0);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
jz4780_gpio_pic_enable_intr(device_t dev, struct intr_irqsrc *isrc)
|
||||||
|
{
|
||||||
|
struct jz4780_gpio_softc *sc;
|
||||||
|
struct jz4780_gpio_pin *pin;
|
||||||
|
|
||||||
|
sc = device_get_softc(dev);
|
||||||
|
pin = __containerof(isrc, struct jz4780_gpio_pin, pin_irqsrc);
|
||||||
|
|
||||||
|
CSR_WRITE_4(sc, JZ_GPIO_MASKC, 1u << pin->pin_num);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
jz4780_gpio_pic_disable_intr(device_t dev, struct intr_irqsrc *isrc)
|
||||||
|
{
|
||||||
|
struct jz4780_gpio_softc *sc;
|
||||||
|
struct jz4780_gpio_pin *pin;
|
||||||
|
|
||||||
|
sc = device_get_softc(dev);
|
||||||
|
pin = __containerof(isrc, struct jz4780_gpio_pin, pin_irqsrc);
|
||||||
|
|
||||||
|
CSR_WRITE_4(sc, JZ_GPIO_MASKS, 1u << pin->pin_num);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
jz4780_gpio_pic_pre_ithread(device_t dev, struct intr_irqsrc *isrc)
|
||||||
|
{
|
||||||
|
|
||||||
|
jz4780_gpio_pic_disable_intr(dev, isrc);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
jz4780_gpio_pic_post_ithread(device_t dev, struct intr_irqsrc *isrc)
|
||||||
|
{
|
||||||
|
|
||||||
|
jz4780_gpio_pic_enable_intr(dev, isrc);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
jz4780_gpio_pic_post_filter(device_t dev, struct intr_irqsrc *isrc)
|
||||||
|
{
|
||||||
|
struct jz4780_gpio_softc *sc;
|
||||||
|
struct jz4780_gpio_pin *pin;
|
||||||
|
|
||||||
|
sc = device_get_softc(dev);
|
||||||
|
pin = __containerof(isrc, struct jz4780_gpio_pin, pin_irqsrc);
|
||||||
|
|
||||||
|
CSR_WRITE_4(sc, JZ_GPIO_FLAGC, 1u << pin->pin_num);
|
||||||
|
}
|
||||||
|
|
||||||
|
static int
|
||||||
|
jz4780_gpio_intr(void *arg)
|
||||||
|
{
|
||||||
|
struct jz4780_gpio_softc *sc;
|
||||||
|
uint32_t i, interrupts;
|
||||||
|
|
||||||
|
sc = arg;
|
||||||
|
interrupts = CSR_READ_4(sc, JZ_GPIO_FLAG);
|
||||||
|
|
||||||
|
for (i = 0; interrupts != 0; i++, interrupts >>= 1) {
|
||||||
|
if ((interrupts & 0x1) == 0)
|
||||||
|
continue;
|
||||||
|
if (intr_isrc_dispatch(&sc->pins[i].pin_irqsrc,
|
||||||
|
curthread->td_intr_frame) != 0) {
|
||||||
|
device_printf(sc->dev, "spurious interrupt %d\n", i);
|
||||||
|
PIC_DISABLE_INTR(sc->dev, &sc->pins[i].pin_irqsrc);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return (FILTER_HANDLED);
|
||||||
|
}
|
||||||
|
|
||||||
|
static device_method_t jz4780_gpio_methods[] = {
|
||||||
|
/* Device interface */
|
||||||
|
DEVMETHOD(device_probe, jz4780_gpio_probe),
|
||||||
|
DEVMETHOD(device_attach, jz4780_gpio_attach),
|
||||||
|
DEVMETHOD(device_detach, jz4780_gpio_detach),
|
||||||
|
|
||||||
|
/* GPIO protocol */
|
||||||
|
DEVMETHOD(gpio_get_bus, jz4780_gpio_get_bus),
|
||||||
|
DEVMETHOD(gpio_pin_max, jz4780_gpio_pin_max),
|
||||||
|
DEVMETHOD(gpio_pin_getname, jz4780_gpio_pin_getname),
|
||||||
|
DEVMETHOD(gpio_pin_getflags, jz4780_gpio_pin_getflags),
|
||||||
|
DEVMETHOD(gpio_pin_getcaps, jz4780_gpio_pin_getcaps),
|
||||||
|
DEVMETHOD(gpio_pin_setflags, jz4780_gpio_pin_setflags),
|
||||||
|
DEVMETHOD(gpio_pin_get, jz4780_gpio_pin_get),
|
||||||
|
DEVMETHOD(gpio_pin_set, jz4780_gpio_pin_set),
|
||||||
|
DEVMETHOD(gpio_pin_toggle, jz4780_gpio_pin_toggle),
|
||||||
|
|
||||||
|
/* Custom interface to set pin function */
|
||||||
|
DEVMETHOD(jz4780_gpio_configure_pin, jz4780_gpio_configure_pin),
|
||||||
|
|
||||||
|
/* Interrupt controller interface */
|
||||||
|
DEVMETHOD(pic_setup_intr, jz4780_gpio_pic_setup_intr),
|
||||||
|
DEVMETHOD(pic_enable_intr, jz4780_gpio_pic_enable_intr),
|
||||||
|
DEVMETHOD(pic_disable_intr, jz4780_gpio_pic_disable_intr),
|
||||||
|
DEVMETHOD(pic_map_intr, jz4780_gpio_pic_map_intr),
|
||||||
|
DEVMETHOD(pic_post_filter, jz4780_gpio_pic_post_filter),
|
||||||
|
DEVMETHOD(pic_post_ithread, jz4780_gpio_pic_post_ithread),
|
||||||
|
DEVMETHOD(pic_pre_ithread, jz4780_gpio_pic_pre_ithread),
|
||||||
|
|
||||||
|
DEVMETHOD_END
|
||||||
|
};
|
||||||
|
|
||||||
|
static driver_t jz4780_gpio_driver = {
|
||||||
|
"gpio",
|
||||||
|
jz4780_gpio_methods,
|
||||||
|
sizeof(struct jz4780_gpio_softc),
|
||||||
|
};
|
||||||
|
|
||||||
|
static devclass_t jz4780_gpio_devclass;
|
||||||
|
|
||||||
|
EARLY_DRIVER_MODULE(jz4780_gpio, simplebus, jz4780_gpio_driver,
|
||||||
|
jz4780_gpio_devclass, 0, 0, BUS_PASS_INTERRUPT + BUS_PASS_ORDER_LATE);
|
41
sys/mips/ingenic/jz4780_gpio_if.m
Normal file
41
sys/mips/ingenic/jz4780_gpio_if.m
Normal file
@ -0,0 +1,41 @@
|
|||||||
|
#-
|
||||||
|
# Copyright (c) 2015 Alexander Kabaev <kan@FreeBSD.org>
|
||||||
|
# All rights reserved.
|
||||||
|
#
|
||||||
|
# Redistribution and use in source and binary forms, with or without
|
||||||
|
# modification, are permitted provided that the following conditions
|
||||||
|
# are met:
|
||||||
|
# 1. Redistributions of source code must retain the above copyright
|
||||||
|
# notice, this list of conditions and the following disclaimer.
|
||||||
|
# 2. Redistributions in binary form must reproduce the above copyright
|
||||||
|
# notice, this list of conditions and the following disclaimer in the
|
||||||
|
# documentation and/or other materials provided with the distribution.
|
||||||
|
#
|
||||||
|
# THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
|
||||||
|
# ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||||
|
# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
||||||
|
# ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
|
||||||
|
# FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
|
||||||
|
# DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
|
||||||
|
# OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
|
||||||
|
# HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
|
||||||
|
# LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
|
||||||
|
# OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
|
||||||
|
# SUCH DAMAGE.
|
||||||
|
#
|
||||||
|
# $FreeBSD$
|
||||||
|
#
|
||||||
|
|
||||||
|
#include <sys/bus.h>
|
||||||
|
|
||||||
|
INTERFACE jz4780_gpio;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Configures pin as specified by FDT pinctrl entry
|
||||||
|
*/
|
||||||
|
METHOD int configure_pin {
|
||||||
|
device_t dev;
|
||||||
|
uint32_t gpio;
|
||||||
|
uint32_t func;
|
||||||
|
uint32_t flags;
|
||||||
|
};
|
333
sys/mips/ingenic/jz4780_intr.c
Normal file
333
sys/mips/ingenic/jz4780_intr.c
Normal file
@ -0,0 +1,333 @@
|
|||||||
|
/*-
|
||||||
|
* Copyright (c) 2015 Alexander Kabaev
|
||||||
|
* 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,
|
||||||
|
* without modification, immediately at the beginning of the file.
|
||||||
|
* 2. The name of the author may not 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 "opt_platform.h"
|
||||||
|
|
||||||
|
#include <sys/cdefs.h>
|
||||||
|
__FBSDID("$FreeBSD$");
|
||||||
|
|
||||||
|
#include <sys/param.h>
|
||||||
|
#include <sys/systm.h>
|
||||||
|
#include <sys/bus.h>
|
||||||
|
#include <sys/kernel.h>
|
||||||
|
#include <sys/ktr.h>
|
||||||
|
#include <sys/module.h>
|
||||||
|
#include <sys/malloc.h>
|
||||||
|
#include <sys/rman.h>
|
||||||
|
#include <sys/pcpu.h>
|
||||||
|
#include <sys/proc.h>
|
||||||
|
#include <sys/cpuset.h>
|
||||||
|
#include <sys/lock.h>
|
||||||
|
#include <sys/mutex.h>
|
||||||
|
#include <sys/smp.h>
|
||||||
|
#include <sys/sched.h>
|
||||||
|
#include <machine/bus.h>
|
||||||
|
#include <machine/intr.h>
|
||||||
|
#include <machine/smp.h>
|
||||||
|
|
||||||
|
#include <dev/fdt/fdt_common.h>
|
||||||
|
#include <dev/ofw/openfirm.h>
|
||||||
|
#include <dev/ofw/ofw_bus.h>
|
||||||
|
#include <dev/ofw/ofw_bus_subr.h>
|
||||||
|
|
||||||
|
#include <mips/ingenic/jz4780_regs.h>
|
||||||
|
|
||||||
|
#include "pic_if.h"
|
||||||
|
|
||||||
|
#define JZ4780_NIRQS 64
|
||||||
|
|
||||||
|
static int jz4780_pic_intr(void *);
|
||||||
|
|
||||||
|
struct jz4780_pic_isrc {
|
||||||
|
struct intr_irqsrc isrc;
|
||||||
|
u_int irq;
|
||||||
|
};
|
||||||
|
|
||||||
|
struct jz4780_pic_softc {
|
||||||
|
device_t pic_dev;
|
||||||
|
void * pic_intrhand;
|
||||||
|
struct resource * pic_res[2];
|
||||||
|
struct jz4780_pic_isrc pic_irqs[JZ4780_NIRQS];
|
||||||
|
uint32_t nirqs;
|
||||||
|
};
|
||||||
|
|
||||||
|
#define PIC_INTR_ISRC(sc, irq) (&(sc)->pic_irqs[(irq)].isrc)
|
||||||
|
|
||||||
|
static struct resource_spec jz4780_pic_spec[] = {
|
||||||
|
{ SYS_RES_MEMORY, 0, RF_ACTIVE }, /* Registers */
|
||||||
|
{ SYS_RES_IRQ, 0, RF_ACTIVE }, /* Parent interrupt */
|
||||||
|
{ -1, 0 }
|
||||||
|
};
|
||||||
|
|
||||||
|
static struct ofw_compat_data compat_data[] = {
|
||||||
|
{"ingenic,jz4780-intc", true},
|
||||||
|
{NULL, false}
|
||||||
|
};
|
||||||
|
|
||||||
|
#define READ4(_sc, _reg) bus_read_4((_sc)->pic_res[0], _reg)
|
||||||
|
#define WRITE4(_sc, _reg, _val) bus_write_4((_sc)->pic_res[0], _reg, _val)
|
||||||
|
|
||||||
|
static int
|
||||||
|
jz4780_pic_probe(device_t dev)
|
||||||
|
{
|
||||||
|
|
||||||
|
if (!ofw_bus_status_okay(dev))
|
||||||
|
return (ENXIO);
|
||||||
|
|
||||||
|
if (!ofw_bus_search_compatible(dev, compat_data)->ocd_data)
|
||||||
|
return (ENXIO);
|
||||||
|
device_set_desc(dev, "JZ4780 Interrupt Controller");
|
||||||
|
return (BUS_PROBE_DEFAULT);
|
||||||
|
}
|
||||||
|
|
||||||
|
static inline void
|
||||||
|
pic_irq_unmask(struct jz4780_pic_softc *sc, u_int irq)
|
||||||
|
{
|
||||||
|
if (irq < 32)
|
||||||
|
WRITE4(sc, JZ_ICMCR0, (1u << irq));
|
||||||
|
else
|
||||||
|
WRITE4(sc, JZ_ICMCR1, (1u << (irq - 32)));
|
||||||
|
}
|
||||||
|
|
||||||
|
static inline void
|
||||||
|
pic_irq_mask(struct jz4780_pic_softc *sc, u_int irq)
|
||||||
|
{
|
||||||
|
if (irq < 32)
|
||||||
|
WRITE4(sc, JZ_ICMSR0, (1u << irq));
|
||||||
|
else
|
||||||
|
WRITE4(sc, JZ_ICMSR1, (1u << (irq - 32)));
|
||||||
|
}
|
||||||
|
|
||||||
|
static inline intptr_t
|
||||||
|
pic_xref(device_t dev)
|
||||||
|
{
|
||||||
|
return (OF_xref_from_node(ofw_bus_get_node(dev)));
|
||||||
|
}
|
||||||
|
|
||||||
|
static int
|
||||||
|
jz4780_pic_register_isrcs(struct jz4780_pic_softc *sc)
|
||||||
|
{
|
||||||
|
int error;
|
||||||
|
uint32_t irq, i;
|
||||||
|
struct intr_irqsrc *isrc;
|
||||||
|
const char *name;
|
||||||
|
|
||||||
|
name = device_get_nameunit(sc->pic_dev);
|
||||||
|
for (irq = 0; irq < sc->nirqs; irq++) {
|
||||||
|
sc->pic_irqs[irq].irq = irq;
|
||||||
|
isrc = PIC_INTR_ISRC(sc, irq);
|
||||||
|
error = intr_isrc_register(isrc, sc->pic_dev, 0, "%s,%d",
|
||||||
|
name, irq);
|
||||||
|
if (error != 0) {
|
||||||
|
for (i = 0; i < irq; i++)
|
||||||
|
intr_isrc_deregister(PIC_INTR_ISRC(sc, irq));
|
||||||
|
device_printf(sc->pic_dev, "%s failed", __func__);
|
||||||
|
return (error);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return (0);
|
||||||
|
}
|
||||||
|
|
||||||
|
static int
|
||||||
|
jz4780_pic_attach(device_t dev)
|
||||||
|
{
|
||||||
|
struct jz4780_pic_softc *sc;
|
||||||
|
intptr_t xref;
|
||||||
|
|
||||||
|
xref = pic_xref(dev);
|
||||||
|
|
||||||
|
sc = device_get_softc(dev);
|
||||||
|
|
||||||
|
if (bus_alloc_resources(dev, jz4780_pic_spec, sc->pic_res)) {
|
||||||
|
device_printf(dev, "could not allocate resources\n");
|
||||||
|
return (ENXIO);
|
||||||
|
}
|
||||||
|
|
||||||
|
sc->pic_dev = dev;
|
||||||
|
|
||||||
|
/* Set the number of interrupts */
|
||||||
|
sc->nirqs = nitems(sc->pic_irqs);
|
||||||
|
|
||||||
|
/* Mask all interrupts */
|
||||||
|
WRITE4(sc, JZ_ICMR0, 0xFFFFFFFF);
|
||||||
|
WRITE4(sc, JZ_ICMR1, 0xFFFFFFFF);
|
||||||
|
|
||||||
|
/* Register the interrupts */
|
||||||
|
if (jz4780_pic_register_isrcs(sc) != 0) {
|
||||||
|
device_printf(dev, "could not register PIC ISRCs\n");
|
||||||
|
goto cleanup;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Now, when everything is initialized, it's right time to
|
||||||
|
* register interrupt controller to interrupt framefork.
|
||||||
|
*/
|
||||||
|
if (intr_pic_register(dev, xref) == NULL) {
|
||||||
|
device_printf(dev, "could not register PIC\n");
|
||||||
|
goto cleanup;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (bus_setup_intr(dev, sc->pic_res[1], INTR_TYPE_CLK,
|
||||||
|
jz4780_pic_intr, NULL, sc, &sc->pic_intrhand)) {
|
||||||
|
device_printf(dev, "could not setup irq handler\n");
|
||||||
|
intr_pic_deregister(dev, xref);
|
||||||
|
goto cleanup;
|
||||||
|
}
|
||||||
|
|
||||||
|
return (0);
|
||||||
|
|
||||||
|
cleanup:
|
||||||
|
bus_release_resources(dev, jz4780_pic_spec, sc->pic_res);
|
||||||
|
|
||||||
|
return(ENXIO);
|
||||||
|
}
|
||||||
|
|
||||||
|
static int
|
||||||
|
jz4780_pic_intr(void *arg)
|
||||||
|
{
|
||||||
|
struct jz4780_pic_softc *sc = arg;
|
||||||
|
struct intr_irqsrc *isrc;
|
||||||
|
struct thread *td;
|
||||||
|
uint32_t i, intr;
|
||||||
|
|
||||||
|
td = curthread;
|
||||||
|
/* Workaround: do not inflate intr nesting level */
|
||||||
|
td->td_intr_nesting_level--;
|
||||||
|
|
||||||
|
intr = READ4(sc, JZ_ICPR0);
|
||||||
|
while ((i = fls(intr)) != 0) {
|
||||||
|
i--;
|
||||||
|
intr &= ~(1u << i);
|
||||||
|
|
||||||
|
isrc = PIC_INTR_ISRC(sc, i);
|
||||||
|
if (intr_isrc_dispatch(isrc, curthread->td_intr_frame) != 0) {
|
||||||
|
device_printf(sc->pic_dev, "Stray interrupt %u detected\n", i);
|
||||||
|
pic_irq_mask(sc, i);
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
KASSERT(i == 0, ("all interrupts handled"));
|
||||||
|
|
||||||
|
intr = READ4(sc, JZ_ICPR1);
|
||||||
|
while ((i = fls(intr)) != 0) {
|
||||||
|
i--;
|
||||||
|
intr &= ~(1u << i);
|
||||||
|
i += 32;
|
||||||
|
|
||||||
|
isrc = PIC_INTR_ISRC(sc, i);
|
||||||
|
if (intr_isrc_dispatch(isrc, curthread->td_intr_frame) != 0) {
|
||||||
|
device_printf(sc->pic_dev, "Stray interrupt %u detected\n", i);
|
||||||
|
pic_irq_mask(sc, i);
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
KASSERT(i == 0, ("all interrupts handled"));
|
||||||
|
td->td_intr_nesting_level++;
|
||||||
|
|
||||||
|
return (FILTER_HANDLED);
|
||||||
|
}
|
||||||
|
|
||||||
|
static int
|
||||||
|
jz4780_pic_map_intr(device_t dev, struct intr_map_data *data,
|
||||||
|
struct intr_irqsrc **isrcp)
|
||||||
|
{
|
||||||
|
#ifdef FDT
|
||||||
|
struct jz4780_pic_softc *sc;
|
||||||
|
struct intr_map_data_fdt *daf;
|
||||||
|
|
||||||
|
sc = device_get_softc(dev);
|
||||||
|
daf = (struct intr_map_data_fdt *)data;
|
||||||
|
|
||||||
|
if (data == NULL || data->type != INTR_MAP_DATA_FDT ||
|
||||||
|
daf->ncells != 1 || daf->cells[0] >= sc->nirqs)
|
||||||
|
return (EINVAL);
|
||||||
|
|
||||||
|
*isrcp = PIC_INTR_ISRC(sc, daf->cells[0]);
|
||||||
|
return (0);
|
||||||
|
#else
|
||||||
|
return (EINVAL);
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
jz4780_pic_enable_intr(device_t dev, struct intr_irqsrc *isrc)
|
||||||
|
{
|
||||||
|
struct jz4780_pic_isrc *pic_isrc;
|
||||||
|
|
||||||
|
pic_isrc = (struct jz4780_pic_isrc *)isrc;
|
||||||
|
pic_irq_unmask(device_get_softc(dev), pic_isrc->irq);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
jz4780_pic_disable_intr(device_t dev, struct intr_irqsrc *isrc)
|
||||||
|
{
|
||||||
|
struct jz4780_pic_isrc *pic_isrc;
|
||||||
|
|
||||||
|
pic_isrc = (struct jz4780_pic_isrc *)isrc;
|
||||||
|
pic_irq_mask(device_get_softc(dev), pic_isrc->irq);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
jz4780_pic_pre_ithread(device_t dev, struct intr_irqsrc *isrc)
|
||||||
|
{
|
||||||
|
|
||||||
|
jz4780_pic_disable_intr(dev, isrc);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
jz4780_pic_post_ithread(device_t dev, struct intr_irqsrc *isrc)
|
||||||
|
{
|
||||||
|
|
||||||
|
jz4780_pic_enable_intr(dev, isrc);
|
||||||
|
}
|
||||||
|
|
||||||
|
static device_method_t jz4780_pic_methods[] = {
|
||||||
|
/* Device interface */
|
||||||
|
DEVMETHOD(device_probe, jz4780_pic_probe),
|
||||||
|
DEVMETHOD(device_attach, jz4780_pic_attach),
|
||||||
|
/* Interrupt controller interface */
|
||||||
|
DEVMETHOD(pic_enable_intr, jz4780_pic_enable_intr),
|
||||||
|
DEVMETHOD(pic_disable_intr, jz4780_pic_disable_intr),
|
||||||
|
DEVMETHOD(pic_map_intr, jz4780_pic_map_intr),
|
||||||
|
DEVMETHOD(pic_post_ithread, jz4780_pic_post_ithread),
|
||||||
|
DEVMETHOD(pic_pre_ithread, jz4780_pic_pre_ithread),
|
||||||
|
{ 0, 0 }
|
||||||
|
};
|
||||||
|
|
||||||
|
static driver_t jz4780_pic_driver = {
|
||||||
|
"intc",
|
||||||
|
jz4780_pic_methods,
|
||||||
|
sizeof(struct jz4780_pic_softc),
|
||||||
|
};
|
||||||
|
|
||||||
|
static devclass_t jz4780_pic_devclass;
|
||||||
|
|
||||||
|
EARLY_DRIVER_MODULE(intc, ofwbus, jz4780_pic_driver, jz4780_pic_devclass, 0, 0,
|
||||||
|
BUS_PASS_INTERRUPT + BUS_PASS_ORDER_MIDDLE);
|
296
sys/mips/ingenic/jz4780_machdep.c
Normal file
296
sys/mips/ingenic/jz4780_machdep.c
Normal file
@ -0,0 +1,296 @@
|
|||||||
|
/*-
|
||||||
|
* Copyright (c) 2009 Oleksandr Tymoshenko
|
||||||
|
* Copyright (c) 2015 Alexander Kabaev
|
||||||
|
* All rights reserved.
|
||||||
|
*
|
||||||
|
* Redistribution and use in source and binary forms, with or without
|
||||||
|
* modification, are permitted provided that the following conditions
|
||||||
|
* are met:
|
||||||
|
* 1. Redistributions of source code must retain the above copyright
|
||||||
|
* notice, this list of conditions and the following disclaimer.
|
||||||
|
* 2. Redistributions in binary form must reproduce the above copyright
|
||||||
|
* notice, this list of conditions and the following disclaimer in the
|
||||||
|
* documentation and/or other materials provided with the distribution.
|
||||||
|
*
|
||||||
|
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
|
||||||
|
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||||
|
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
||||||
|
* ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
|
||||||
|
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
|
||||||
|
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
|
||||||
|
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
|
||||||
|
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
|
||||||
|
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
|
||||||
|
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
|
||||||
|
* SUCH DAMAGE.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include <sys/cdefs.h>
|
||||||
|
__FBSDID("$FreeBSD$");
|
||||||
|
|
||||||
|
#include "opt_ddb.h"
|
||||||
|
#include "opt_platform.h"
|
||||||
|
|
||||||
|
#include <sys/param.h>
|
||||||
|
#include <sys/conf.h>
|
||||||
|
#include <sys/kernel.h>
|
||||||
|
#include <sys/systm.h>
|
||||||
|
#include <sys/bus.h>
|
||||||
|
#include <sys/cons.h>
|
||||||
|
#include <sys/kdb.h>
|
||||||
|
#include <sys/reboot.h>
|
||||||
|
|
||||||
|
#ifdef FDT
|
||||||
|
#include <dev/fdt/fdt_common.h>
|
||||||
|
#include <dev/ofw/openfirm.h>
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#include <vm/vm.h>
|
||||||
|
#include <vm/vm_page.h>
|
||||||
|
|
||||||
|
#include <net/ethernet.h>
|
||||||
|
|
||||||
|
#include <machine/clock.h>
|
||||||
|
#include <machine/cpu.h>
|
||||||
|
#include <machine/cpufunc.h>
|
||||||
|
#include <machine/hwfunc.h>
|
||||||
|
#include <machine/md_var.h>
|
||||||
|
#include <machine/trap.h>
|
||||||
|
#include <machine/vmparam.h>
|
||||||
|
|
||||||
|
#include <mips/ingenic/jz4780_regs.h>
|
||||||
|
#include <mips/ingenic/jz4780_cpuregs.h>
|
||||||
|
|
||||||
|
uint32_t * const led = (uint32_t *)0xb0010548;
|
||||||
|
|
||||||
|
extern char edata[], end[];
|
||||||
|
static char boot1_env[4096];
|
||||||
|
|
||||||
|
void
|
||||||
|
platform_cpu_init(void)
|
||||||
|
{
|
||||||
|
uint32_t reg;
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Do not expect mbox interrups while writing
|
||||||
|
* mbox
|
||||||
|
*/
|
||||||
|
reg = mips_rd_xburst_reim();
|
||||||
|
reg &= ~JZ_REIM_MIRQ0M;
|
||||||
|
mips_wr_xburst_reim(reg);
|
||||||
|
|
||||||
|
/* Clean mailboxes */
|
||||||
|
mips_wr_xburst_mbox0(0);
|
||||||
|
mips_wr_xburst_mbox1(0);
|
||||||
|
mips_wr_xburst_core_sts(~JZ_CORESTS_MIRQ0P);
|
||||||
|
|
||||||
|
/* Unmask mbox interrupts */
|
||||||
|
reg |= JZ_REIM_MIRQ0M;
|
||||||
|
mips_wr_xburst_reim(reg);
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
platform_reset(void)
|
||||||
|
{
|
||||||
|
/*
|
||||||
|
* For now, provoke a watchdog reset in about a second, so UART buffers
|
||||||
|
* have a fighting chance to flush before we pull the plug
|
||||||
|
*/
|
||||||
|
writereg(JZ_TCU_BASE + JZ_WDOG_TCER, 0); /* disable watchdog */
|
||||||
|
writereg(JZ_TCU_BASE + JZ_WDOG_TCNT, 0); /* reset counter */
|
||||||
|
writereg(JZ_TCU_BASE + JZ_WDOG_TDR, 128); /* wait for ~1s */
|
||||||
|
writereg(JZ_TCU_BASE + JZ_WDOG_TCSR, TCSR_RTC_EN | TCSR_DIV_256);
|
||||||
|
writereg(JZ_TCU_BASE + JZ_WDOG_TCER, TCER_ENABLE); /* fire! */
|
||||||
|
|
||||||
|
/* Wait for reset */
|
||||||
|
while (1)
|
||||||
|
;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
mips_init(void)
|
||||||
|
{
|
||||||
|
int i;
|
||||||
|
#ifdef FDT
|
||||||
|
struct mem_region mr[FDT_MEM_REGIONS];
|
||||||
|
uint64_t val;
|
||||||
|
int mr_cnt;
|
||||||
|
int j;
|
||||||
|
#endif
|
||||||
|
|
||||||
|
for (i = 0; i < 10; i++) {
|
||||||
|
phys_avail[i] = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* The minimal amount of memory Ingenic SoC can have. */
|
||||||
|
dump_avail[0] = phys_avail[0] = MIPS_KSEG0_TO_PHYS(kernel_kseg0_end);
|
||||||
|
physmem = realmem = btoc(32 * 1024 * 1024);
|
||||||
|
|
||||||
|
/*
|
||||||
|
* X1000 mips cpu special.
|
||||||
|
* TODO: do anyone know what is this ?
|
||||||
|
*/
|
||||||
|
__asm(
|
||||||
|
"li $2, 0xa9000000 \n\t"
|
||||||
|
"mtc0 $2, $5, 4 \n\t"
|
||||||
|
"nop \n\t"
|
||||||
|
::"r"(2));
|
||||||
|
|
||||||
|
#ifdef FDT
|
||||||
|
if (fdt_get_mem_regions(mr, &mr_cnt, &val) == 0) {
|
||||||
|
|
||||||
|
physmem = realmem = btoc(val);
|
||||||
|
|
||||||
|
KASSERT((phys_avail[0] >= mr[0].mr_start) && \
|
||||||
|
(phys_avail[0] < (mr[0].mr_start + mr[0].mr_size)),
|
||||||
|
("First region is not within FDT memory range"));
|
||||||
|
|
||||||
|
/* Limit size of the first region */
|
||||||
|
phys_avail[1] = (mr[0].mr_start + MIN(mr[0].mr_size, ctob(realmem)));
|
||||||
|
dump_avail[1] = phys_avail[1];
|
||||||
|
|
||||||
|
/* Add the rest of regions */
|
||||||
|
for (i = 1, j = 2; i < mr_cnt; i++, j+=2) {
|
||||||
|
phys_avail[j] = mr[i].mr_start;
|
||||||
|
phys_avail[j+1] = (mr[i].mr_start + mr[i].mr_size);
|
||||||
|
dump_avail[j] = phys_avail[j];
|
||||||
|
dump_avail[j+1] = phys_avail[j+1];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
init_param1();
|
||||||
|
init_param2(physmem);
|
||||||
|
mips_cpu_init();
|
||||||
|
pmap_bootstrap();
|
||||||
|
mips_proc0_init();
|
||||||
|
mutex_init();
|
||||||
|
kdb_init();
|
||||||
|
led[0] = 0x8000;
|
||||||
|
#ifdef KDB
|
||||||
|
if (boothowto & RB_KDB)
|
||||||
|
kdb_enter(KDB_WHY_BOOTFLAGS, "Boot flags requested debugger");
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
_parse_bootarg(char *v)
|
||||||
|
{
|
||||||
|
char *n;
|
||||||
|
|
||||||
|
if (*v == '-') {
|
||||||
|
while (*v != '\0') {
|
||||||
|
v++;
|
||||||
|
switch (*v) {
|
||||||
|
case 'a': boothowto |= RB_ASKNAME; break;
|
||||||
|
/* Someone should simulate that ;-) */
|
||||||
|
case 'C': boothowto |= RB_CDROM; break;
|
||||||
|
case 'd': boothowto |= RB_KDB; break;
|
||||||
|
case 'D': boothowto |= RB_MULTIPLE; break;
|
||||||
|
case 'm': boothowto |= RB_MUTE; break;
|
||||||
|
case 'g': boothowto |= RB_GDB; break;
|
||||||
|
case 'h': boothowto |= RB_SERIAL; break;
|
||||||
|
case 'p': boothowto |= RB_PAUSE; break;
|
||||||
|
case 'r': boothowto |= RB_DFLTROOT; break;
|
||||||
|
case 's': boothowto |= RB_SINGLE; break;
|
||||||
|
case 'v': boothowto |= RB_VERBOSE; break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
n = strsep(&v, "=");
|
||||||
|
if (v == NULL)
|
||||||
|
kern_setenv(n, "1");
|
||||||
|
else
|
||||||
|
kern_setenv(n, v);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
_parse_cmdline(int argc, char *argv[])
|
||||||
|
{
|
||||||
|
int i;
|
||||||
|
|
||||||
|
for (i = 1; i < argc; i++)
|
||||||
|
_parse_bootarg(argv[i]);
|
||||||
|
}
|
||||||
|
|
||||||
|
#ifdef FDT
|
||||||
|
/* Parse cmd line args as env - copied from xlp_machdep. */
|
||||||
|
/* XXX-BZ this should really be centrally provided for all (boot) code. */
|
||||||
|
static void
|
||||||
|
_parse_bootargs(char *cmdline)
|
||||||
|
{
|
||||||
|
char *v;
|
||||||
|
|
||||||
|
while ((v = strsep(&cmdline, " \n")) != NULL) {
|
||||||
|
if (*v == '\0')
|
||||||
|
continue;
|
||||||
|
_parse_bootarg(v);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
void
|
||||||
|
platform_start(__register_t a0, __register_t a1,
|
||||||
|
__register_t a2 __unused, __register_t a3 __unused)
|
||||||
|
{
|
||||||
|
char **argv;
|
||||||
|
int argc;
|
||||||
|
vm_offset_t kernend;
|
||||||
|
#ifdef FDT
|
||||||
|
vm_offset_t dtbp;
|
||||||
|
phandle_t chosen;
|
||||||
|
char buf[2048]; /* early stack supposedly big enough */
|
||||||
|
#endif
|
||||||
|
/*
|
||||||
|
* clear the BSS and SBSS segments, this should be first call in
|
||||||
|
* the function
|
||||||
|
*/
|
||||||
|
kernend = (vm_offset_t)&end;
|
||||||
|
memset(&edata, 0, kernend - (vm_offset_t)(&edata));
|
||||||
|
|
||||||
|
mips_postboot_fixup();
|
||||||
|
|
||||||
|
/* Initialize pcpu stuff */
|
||||||
|
mips_pcpu0_init();
|
||||||
|
|
||||||
|
/* Something to hold kernel env until kmem is available */
|
||||||
|
init_static_kenv(boot1_env, sizeof(boot1_env));
|
||||||
|
#ifdef FDT
|
||||||
|
/*
|
||||||
|
* Find the dtb passed in by the boot loader (currently fictional).
|
||||||
|
*/
|
||||||
|
dtbp = (vm_offset_t)NULL;
|
||||||
|
|
||||||
|
#if defined(FDT_DTB_STATIC)
|
||||||
|
/*
|
||||||
|
* In case the device tree blob was not retrieved (from metadata) try
|
||||||
|
* to use the statically embedded one.
|
||||||
|
*/
|
||||||
|
if (dtbp == (vm_offset_t)NULL)
|
||||||
|
dtbp = (vm_offset_t)&fdt_static_dtb;
|
||||||
|
#else
|
||||||
|
#error "Non-static FDT not supported on JZ4780"
|
||||||
|
#endif
|
||||||
|
if (OF_install(OFW_FDT, 0) == FALSE)
|
||||||
|
while (1);
|
||||||
|
if (OF_init((void *)dtbp) != 0)
|
||||||
|
while (1);
|
||||||
|
#endif
|
||||||
|
|
||||||
|
cninit();
|
||||||
|
#ifdef FDT
|
||||||
|
/*
|
||||||
|
* Get bootargs from FDT if specified.
|
||||||
|
*/
|
||||||
|
chosen = OF_finddevice("/chosen");
|
||||||
|
if (OF_getprop(chosen, "bootargs", buf, sizeof(buf)) != -1)
|
||||||
|
_parse_bootargs(buf);
|
||||||
|
#endif
|
||||||
|
/* Parse cmdline from U-Boot */
|
||||||
|
argc = a0;
|
||||||
|
argv = (char **)a1;
|
||||||
|
_parse_cmdline(argc, argv);
|
||||||
|
|
||||||
|
mips_init();
|
||||||
|
}
|
1002
sys/mips/ingenic/jz4780_mmc.c
Normal file
1002
sys/mips/ingenic/jz4780_mmc.c
Normal file
File diff suppressed because it is too large
Load Diff
182
sys/mips/ingenic/jz4780_mp.c
Normal file
182
sys/mips/ingenic/jz4780_mp.c
Normal file
@ -0,0 +1,182 @@
|
|||||||
|
/*-
|
||||||
|
* Copyright (c) 2015 Alexander Kabaev <kan@FreeBSD.org>
|
||||||
|
* Copyright (c) 2004-2010 Juli Mallett <jmallett@FreeBSD.org>
|
||||||
|
* All rights reserved.
|
||||||
|
*
|
||||||
|
* Redistribution and use in source and binary forms, with or without
|
||||||
|
* modification, are permitted provided that the following conditions
|
||||||
|
* are met:
|
||||||
|
* 1. Redistributions of source code must retain the above copyright
|
||||||
|
* notice, this list of conditions and the following disclaimer.
|
||||||
|
* 2. Redistributions in binary form must reproduce the above copyright
|
||||||
|
* notice, this list of conditions and the following disclaimer in the
|
||||||
|
* documentation and/or other materials provided with the distribution.
|
||||||
|
*
|
||||||
|
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
|
||||||
|
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||||
|
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
||||||
|
* ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
|
||||||
|
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
|
||||||
|
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
|
||||||
|
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
|
||||||
|
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
|
||||||
|
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
|
||||||
|
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
|
||||||
|
* SUCH DAMAGE.
|
||||||
|
*
|
||||||
|
* $FreeBSD$
|
||||||
|
*/
|
||||||
|
#include <sys/cdefs.h>
|
||||||
|
__FBSDID("$FreeBSD$");
|
||||||
|
|
||||||
|
#include <sys/param.h>
|
||||||
|
#include <sys/conf.h>
|
||||||
|
#include <sys/kernel.h>
|
||||||
|
#include <sys/smp.h>
|
||||||
|
#include <sys/systm.h>
|
||||||
|
|
||||||
|
#include <machine/cpufunc.h>
|
||||||
|
#include <machine/hwfunc.h>
|
||||||
|
#include <machine/md_var.h>
|
||||||
|
#include <machine/smp.h>
|
||||||
|
|
||||||
|
#include <mips/ingenic/jz4780_regs.h>
|
||||||
|
#include <mips/ingenic/jz4780_cpuregs.h>
|
||||||
|
|
||||||
|
void jz4780_mpentry(void);
|
||||||
|
|
||||||
|
#define JZ4780_MAXCPU 2
|
||||||
|
|
||||||
|
void
|
||||||
|
platform_ipi_send(int cpuid)
|
||||||
|
{
|
||||||
|
|
||||||
|
if (cpuid == 0)
|
||||||
|
mips_wr_xburst_mbox0(1);
|
||||||
|
else
|
||||||
|
mips_wr_xburst_mbox1(1);
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
platform_ipi_clear(void)
|
||||||
|
{
|
||||||
|
int cpuid = PCPU_GET(cpuid);
|
||||||
|
uint32_t action;
|
||||||
|
|
||||||
|
action = (cpuid == 0) ? mips_rd_xburst_mbox0() : mips_rd_xburst_mbox1();
|
||||||
|
KASSERT(action == 1, ("CPU %d: unexpected IPIs: %#x", cpuid, action));
|
||||||
|
mips_wr_xburst_core_sts(~(JZ_CORESTS_MIRQ0P << cpuid));
|
||||||
|
}
|
||||||
|
|
||||||
|
int
|
||||||
|
platform_processor_id(void)
|
||||||
|
{
|
||||||
|
|
||||||
|
return (mips_rd_ebase() & 7);
|
||||||
|
}
|
||||||
|
|
||||||
|
int
|
||||||
|
platform_ipi_hardintr_num(void)
|
||||||
|
{
|
||||||
|
|
||||||
|
return (1);
|
||||||
|
}
|
||||||
|
|
||||||
|
int
|
||||||
|
platform_ipi_softintr_num(void)
|
||||||
|
{
|
||||||
|
|
||||||
|
return (-1);
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
platform_init_ap(int cpuid)
|
||||||
|
{
|
||||||
|
unsigned reg;
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Clear any pending IPIs.
|
||||||
|
*/
|
||||||
|
mips_wr_xburst_core_sts(~(JZ_CORESTS_MIRQ0P << cpuid));
|
||||||
|
|
||||||
|
/* Allow IPI mbox for this core */
|
||||||
|
reg = mips_rd_xburst_reim();
|
||||||
|
reg |= (JZ_REIM_MIRQ0M << cpuid);
|
||||||
|
mips_wr_xburst_reim(reg);
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Unmask the ipi interrupts.
|
||||||
|
*/
|
||||||
|
reg = hard_int_mask(platform_ipi_hardintr_num());
|
||||||
|
set_intr_mask(reg);
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
platform_cpu_mask(cpuset_t *mask)
|
||||||
|
{
|
||||||
|
uint32_t i, m;
|
||||||
|
|
||||||
|
CPU_ZERO(mask);
|
||||||
|
for (i = 0, m = 1 ; i < JZ4780_MAXCPU; i++, m <<= 1)
|
||||||
|
CPU_SET(i, mask);
|
||||||
|
}
|
||||||
|
|
||||||
|
struct cpu_group *
|
||||||
|
platform_smp_topo(void)
|
||||||
|
{
|
||||||
|
return (smp_topo_none());
|
||||||
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
jz4780_core_powerup(void)
|
||||||
|
{
|
||||||
|
uint32_t reg;
|
||||||
|
|
||||||
|
reg = readreg(JZ_CGU_BASE + JZ_LPCR);
|
||||||
|
reg &= ~LPCR_PD_SCPU;
|
||||||
|
writereg(JZ_CGU_BASE + JZ_LPCR, reg);
|
||||||
|
do {
|
||||||
|
reg = readreg(JZ_CGU_BASE + JZ_LPCR);
|
||||||
|
} while ((reg & LPCR_SCPUS) != 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Spin up the second code. The code is roughly modeled after
|
||||||
|
* similar routine in Linux.
|
||||||
|
*/
|
||||||
|
int
|
||||||
|
platform_start_ap(int cpuid)
|
||||||
|
{
|
||||||
|
uint32_t reg, addr;
|
||||||
|
|
||||||
|
if (cpuid >= JZ4780_MAXCPU)
|
||||||
|
return (EINVAL);
|
||||||
|
|
||||||
|
/* Figure out address of mpentry in KSEG1 */
|
||||||
|
addr = MIPS_PHYS_TO_KSEG1(MIPS_KSEG0_TO_PHYS(jz4780_mpentry));
|
||||||
|
KASSERT((addr & ~JZ_REIM_ENTRY_MASK) == 0,
|
||||||
|
("Unaligned mpentry"));
|
||||||
|
|
||||||
|
/* Configure core alternative entry point */
|
||||||
|
reg = mips_rd_xburst_reim();
|
||||||
|
reg &= ~JZ_REIM_ENTRY_MASK;
|
||||||
|
reg |= addr & JZ_REIM_ENTRY_MASK;
|
||||||
|
|
||||||
|
/* Allow this core to get IPIs from one being started */
|
||||||
|
reg |= JZ_REIM_MIRQ0M;
|
||||||
|
mips_wr_xburst_reim(reg);
|
||||||
|
|
||||||
|
/* Force core into reset and enable use of alternate entry point */
|
||||||
|
reg = mips_rd_xburst_core_ctl();
|
||||||
|
reg |= (JZ_CORECTL_SWRST0 << cpuid) | (JZ_CORECTL_RPC0 << cpuid);
|
||||||
|
mips_wr_xburst_core_ctl(reg);
|
||||||
|
|
||||||
|
/* Power the core up */
|
||||||
|
jz4780_core_powerup();
|
||||||
|
|
||||||
|
/* Take the core out of reset */
|
||||||
|
reg &= ~(JZ_CORECTL_SWRST0 << cpuid);
|
||||||
|
mips_wr_xburst_core_ctl(reg);
|
||||||
|
|
||||||
|
return (0);
|
||||||
|
}
|
62
sys/mips/ingenic/jz4780_mpboot.S
Normal file
62
sys/mips/ingenic/jz4780_mpboot.S
Normal file
@ -0,0 +1,62 @@
|
|||||||
|
/*-
|
||||||
|
* Copyright (c) 2015 Alexander Kabaev
|
||||||
|
* 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 <machine/asm.h>
|
||||||
|
#include <machine/cpu.h>
|
||||||
|
#include <machine/cpuregs.h>
|
||||||
|
#include <machine/cache_r4k.h>
|
||||||
|
|
||||||
|
#include "assym.s"
|
||||||
|
|
||||||
|
#define CACHE_SIZE (32 * 1024)
|
||||||
|
#define CACHE_LINESIZE 32
|
||||||
|
|
||||||
|
.text
|
||||||
|
.set noat
|
||||||
|
.set noreorder
|
||||||
|
.section .text.mpentry_jz4780
|
||||||
|
.balign 0x10000
|
||||||
|
|
||||||
|
GLOBAL(jz4780_mpentry)
|
||||||
|
|
||||||
|
/* Initialize caches */
|
||||||
|
li t0, MIPS_KSEG0_START
|
||||||
|
ori t1, t0, CACHE_SIZE
|
||||||
|
mtc0 zero, MIPS_COP_0_TAG_LO
|
||||||
|
COP0_SYNC
|
||||||
|
1: cache CACHEOP_R4K_INDEX_STORE_TAG | CACHE_R4K_I, 0(t0)
|
||||||
|
cache CACHEOP_R4K_INDEX_STORE_TAG | CACHE_R4K_D, 0(t0)
|
||||||
|
bne t0, t1, 1b
|
||||||
|
addiu t0, t0, CACHE_LINESIZE
|
||||||
|
|
||||||
|
/* Set TLB page mask */
|
||||||
|
mtc0 zero, MIPS_COP_0_TLB_PG_MASK
|
||||||
|
COP0_SYNC
|
||||||
|
|
||||||
|
j mpentry
|
||||||
|
nop
|
123
sys/mips/ingenic/jz4780_nand.c
Normal file
123
sys/mips/ingenic/jz4780_nand.c
Normal file
@ -0,0 +1,123 @@
|
|||||||
|
/*-
|
||||||
|
* Copyright 2015 Alexander Kabaev <kan@FreeBSD.org>
|
||||||
|
* All rights reserved.
|
||||||
|
*
|
||||||
|
* Redistribution and use in source and binary forms, with or without
|
||||||
|
* modification, are permitted provided that the following conditions
|
||||||
|
* are met:
|
||||||
|
* 1. Redistributions of source code must retain the above copyright
|
||||||
|
* notice, this list of conditions and the following disclaimer.
|
||||||
|
* 2. Redistributions in binary form must reproduce the above copyright
|
||||||
|
* notice, this list of conditions and the following disclaimer in the
|
||||||
|
* documentation and/or other materials provided with the distribution.
|
||||||
|
*
|
||||||
|
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
|
||||||
|
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||||
|
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
||||||
|
* ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
|
||||||
|
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
|
||||||
|
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
|
||||||
|
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
|
||||||
|
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
|
||||||
|
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
|
||||||
|
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
|
||||||
|
* SUCH DAMAGE.
|
||||||
|
*/
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Ingenic JZ4780 NAND and External Memory Controller (NEMC) driver.
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include <sys/cdefs.h>
|
||||||
|
__FBSDID("$FreeBSD$");
|
||||||
|
|
||||||
|
#include <sys/param.h>
|
||||||
|
#include <sys/systm.h>
|
||||||
|
#include <sys/conf.h>
|
||||||
|
#include <sys/bus.h>
|
||||||
|
#include <sys/kernel.h>
|
||||||
|
#include <sys/module.h>
|
||||||
|
#include <sys/lock.h>
|
||||||
|
#include <sys/mutex.h>
|
||||||
|
#include <sys/resource.h>
|
||||||
|
#include <sys/rman.h>
|
||||||
|
|
||||||
|
#include <machine/bus.h>
|
||||||
|
|
||||||
|
#include <dev/fdt/fdt_common.h>
|
||||||
|
#include <dev/ofw/ofw_bus.h>
|
||||||
|
#include <dev/ofw/ofw_bus_subr.h>
|
||||||
|
|
||||||
|
struct jz4780_nand_softc {
|
||||||
|
device_t dev;
|
||||||
|
struct resource *res[1];
|
||||||
|
};
|
||||||
|
|
||||||
|
static struct resource_spec jz4780_nand_spec[] = {
|
||||||
|
{ SYS_RES_MEMORY, 0, RF_ACTIVE },
|
||||||
|
{ -1, 0 }
|
||||||
|
};
|
||||||
|
|
||||||
|
static int jz4780_nand_probe(device_t dev);
|
||||||
|
static int jz4780_nand_attach(device_t dev);
|
||||||
|
static int jz4780_nand_detach(device_t dev);
|
||||||
|
|
||||||
|
static int
|
||||||
|
jz4780_nand_probe(device_t dev)
|
||||||
|
{
|
||||||
|
|
||||||
|
if (!ofw_bus_status_okay(dev))
|
||||||
|
return (ENXIO);
|
||||||
|
|
||||||
|
if (!ofw_bus_is_compatible(dev, "ingenic,jz4780-nand"))
|
||||||
|
return (ENXIO);
|
||||||
|
|
||||||
|
device_set_desc(dev, "Ingenic JZ4780 NAND Controller");
|
||||||
|
|
||||||
|
return (BUS_PROBE_DEFAULT);
|
||||||
|
}
|
||||||
|
|
||||||
|
static int
|
||||||
|
jz4780_nand_attach(device_t dev)
|
||||||
|
{
|
||||||
|
struct jz4780_nand_softc *sc = device_get_softc(dev);
|
||||||
|
|
||||||
|
sc->dev = dev;
|
||||||
|
|
||||||
|
if (bus_alloc_resources(dev, jz4780_nand_spec, sc->res)) {
|
||||||
|
device_printf(dev, "could not allocate resources for device\n");
|
||||||
|
return (ENXIO);
|
||||||
|
}
|
||||||
|
|
||||||
|
return (0);
|
||||||
|
}
|
||||||
|
|
||||||
|
static int
|
||||||
|
jz4780_nand_detach(device_t dev)
|
||||||
|
{
|
||||||
|
struct jz4780_nand_softc *sc = device_get_softc(dev);
|
||||||
|
|
||||||
|
bus_release_resources(dev, jz4780_nand_spec, sc->res);
|
||||||
|
return (0);
|
||||||
|
}
|
||||||
|
|
||||||
|
static device_method_t jz4780_nand_methods[] = {
|
||||||
|
/* Device interface */
|
||||||
|
DEVMETHOD(device_probe, jz4780_nand_probe),
|
||||||
|
DEVMETHOD(device_attach, jz4780_nand_attach),
|
||||||
|
DEVMETHOD(device_detach, jz4780_nand_detach),
|
||||||
|
|
||||||
|
DEVMETHOD_END
|
||||||
|
};
|
||||||
|
|
||||||
|
static driver_t jz4780_nand_driver = {
|
||||||
|
"nand",
|
||||||
|
jz4780_nand_methods,
|
||||||
|
sizeof(struct jz4780_nand_softc),
|
||||||
|
};
|
||||||
|
|
||||||
|
static devclass_t jz4780_nand_devclass;
|
||||||
|
|
||||||
|
DRIVER_MODULE(jz4780_nand, simplebus, jz4780_nand_driver,
|
||||||
|
jz4780_nand_devclass, 0, 0);
|
373
sys/mips/ingenic/jz4780_nemc.c
Normal file
373
sys/mips/ingenic/jz4780_nemc.c
Normal file
@ -0,0 +1,373 @@
|
|||||||
|
/*-
|
||||||
|
* Copyright 2015 Alexander Kabaev <kan@FreeBSD.org>
|
||||||
|
* All rights reserved.
|
||||||
|
*
|
||||||
|
* Redistribution and use in source and binary forms, with or without
|
||||||
|
* modification, are permitted provided that the following conditions
|
||||||
|
* are met:
|
||||||
|
* 1. Redistributions of source code must retain the above copyright
|
||||||
|
* notice, this list of conditions and the following disclaimer.
|
||||||
|
* 2. Redistributions in binary form must reproduce the above copyright
|
||||||
|
* notice, this list of conditions and the following disclaimer in the
|
||||||
|
* documentation and/or other materials provided with the distribution.
|
||||||
|
*
|
||||||
|
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
|
||||||
|
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||||
|
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
||||||
|
* ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
|
||||||
|
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
|
||||||
|
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
|
||||||
|
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
|
||||||
|
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
|
||||||
|
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
|
||||||
|
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
|
||||||
|
* SUCH DAMAGE.
|
||||||
|
*/
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Ingenic JZ4780 NAND and External Memory Controller (NEMC) driver.
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include <sys/cdefs.h>
|
||||||
|
__FBSDID("$FreeBSD$");
|
||||||
|
|
||||||
|
#include <sys/param.h>
|
||||||
|
#include <sys/systm.h>
|
||||||
|
#include <sys/conf.h>
|
||||||
|
#include <sys/bus.h>
|
||||||
|
#include <sys/kernel.h>
|
||||||
|
#include <sys/module.h>
|
||||||
|
#include <sys/lock.h>
|
||||||
|
#include <sys/mutex.h>
|
||||||
|
#include <sys/resource.h>
|
||||||
|
#include <sys/rman.h>
|
||||||
|
|
||||||
|
#include <machine/bus.h>
|
||||||
|
|
||||||
|
#include <dev/extres/clk/clk.h>
|
||||||
|
|
||||||
|
#include <dev/fdt/fdt_common.h>
|
||||||
|
#include <dev/fdt/simplebus.h>
|
||||||
|
#include <dev/ofw/ofw_bus.h>
|
||||||
|
#include <dev/ofw/ofw_bus_subr.h>
|
||||||
|
|
||||||
|
#include <mips/ingenic/jz4780_regs.h>
|
||||||
|
|
||||||
|
struct jz4780_nemc_devinfo {
|
||||||
|
struct simplebus_devinfo sinfo;
|
||||||
|
uint32_t bank;
|
||||||
|
};
|
||||||
|
|
||||||
|
struct jz4780_nemc_softc {
|
||||||
|
struct simplebus_softc simplebus_sc;
|
||||||
|
device_t dev;
|
||||||
|
struct resource *res[1];
|
||||||
|
uint32_t banks;
|
||||||
|
uint32_t clock_tick_psecs;
|
||||||
|
clk_t clk;
|
||||||
|
};
|
||||||
|
|
||||||
|
static struct resource_spec jz4780_nemc_spec[] = {
|
||||||
|
{ SYS_RES_MEMORY, 0, RF_ACTIVE },
|
||||||
|
{ -1, 0 }
|
||||||
|
};
|
||||||
|
|
||||||
|
#define CSR_WRITE_4(sc, reg, val) bus_write_4((sc)->res[0], reg, (val))
|
||||||
|
#define CSR_READ_4(sc, reg) bus_read_4((sc)->res[0], reg)
|
||||||
|
|
||||||
|
static int jz4780_nemc_probe(device_t dev);
|
||||||
|
static int jz4780_nemc_attach(device_t dev);
|
||||||
|
static int jz4780_nemc_detach(device_t dev);
|
||||||
|
|
||||||
|
static int
|
||||||
|
jz4780_nemc_probe(device_t dev)
|
||||||
|
{
|
||||||
|
|
||||||
|
if (!ofw_bus_status_okay(dev))
|
||||||
|
return (ENXIO);
|
||||||
|
|
||||||
|
if (!ofw_bus_is_compatible(dev, "ingenic,jz4780-nemc"))
|
||||||
|
return (ENXIO);
|
||||||
|
|
||||||
|
device_set_desc(dev, "Ingenic JZ4780 NEMC");
|
||||||
|
|
||||||
|
return (BUS_PROBE_DEFAULT);
|
||||||
|
}
|
||||||
|
|
||||||
|
#define JZ4780_NEMC_NS_TO_TICKS(sc, val) howmany((val) * 1000, (sc)->clock_tick_psecs)
|
||||||
|
|
||||||
|
/* Use table from JZ4780 programmers manual to convert ticks to tBP/tAW register values */
|
||||||
|
static const uint8_t ticks_to_tBP_tAW[32] = {
|
||||||
|
0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, /* 1:1 mapping */
|
||||||
|
11, 11, /* 12 cycles */
|
||||||
|
12, 12, 12, /* 15 cycles */
|
||||||
|
13, 13, 13, 13, 13, /* 20 cycles */
|
||||||
|
14, 14, 14, 14, 14, /* 25 cycles */
|
||||||
|
15, 15, 15, 15, 15, 15 /* 31 cycles */
|
||||||
|
};
|
||||||
|
|
||||||
|
static int
|
||||||
|
jz4780_nemc_configure_bank(struct jz4780_nemc_softc *sc,
|
||||||
|
device_t dev, u_int bank)
|
||||||
|
{
|
||||||
|
uint32_t smcr, cycles;
|
||||||
|
phandle_t node;
|
||||||
|
pcell_t val;
|
||||||
|
|
||||||
|
/* Check if bank is configured already */
|
||||||
|
if (sc->banks & (1 << bank))
|
||||||
|
return 0;
|
||||||
|
|
||||||
|
smcr = CSR_READ_4(sc, JZ_NEMC_SMCR(bank));
|
||||||
|
|
||||||
|
smcr &= ~JZ_NEMC_SMCR_SMT_MASK;
|
||||||
|
smcr |= JZ_NEMC_SMCR_SMT_NORMAL << JZ_NEMC_SMCR_SMT_SHIFT;
|
||||||
|
|
||||||
|
node = ofw_bus_get_node(dev);
|
||||||
|
if (OF_getencprop(node, "ingenic,nemc-tAS", &val, sizeof(val)) > 0) {
|
||||||
|
cycles = JZ4780_NEMC_NS_TO_TICKS(sc, val);
|
||||||
|
if (cycles > 15) {
|
||||||
|
device_printf(sc->dev,
|
||||||
|
"invalid value of %s %u (%u cycles), maximum %u cycles supported\n",
|
||||||
|
"ingenic,nemc-tAS", val, cycles, 15);
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
smcr &= ~JZ_NEMC_SMCR_TAS_MASK;
|
||||||
|
smcr |= cycles << JZ_NEMC_SMCR_TAS_SHIFT;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (OF_getencprop(node, "ingenic,nemc-tAH", &val, sizeof(val)) > 0) {
|
||||||
|
cycles = JZ4780_NEMC_NS_TO_TICKS(sc, val);
|
||||||
|
if (cycles > 15) {
|
||||||
|
device_printf(sc->dev,
|
||||||
|
"invalid value of %s %u (%u cycles), maximum %u cycles supported\n",
|
||||||
|
"ingenic,nemc-tAH", val, cycles, 15);
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
smcr &= ~JZ_NEMC_SMCR_TAH_MASK;
|
||||||
|
smcr |= cycles << JZ_NEMC_SMCR_TAH_SHIFT;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (OF_getencprop(node, "ingenic,nemc-tBP", &val, sizeof(val)) > 0) {
|
||||||
|
cycles = JZ4780_NEMC_NS_TO_TICKS(sc, val);
|
||||||
|
if (cycles > 31) {
|
||||||
|
device_printf(sc->dev,
|
||||||
|
"invalid value of %s %u (%u cycles), maximum %u cycles supported\n",
|
||||||
|
"ingenic,nemc-tBP", val, cycles, 15);
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
smcr &= ~JZ_NEMC_SMCR_TBP_MASK;
|
||||||
|
smcr |= ticks_to_tBP_tAW[cycles] << JZ_NEMC_SMCR_TBP_SHIFT;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (OF_getencprop(node, "ingenic,nemc-tAW", &val, sizeof(val)) > 0) {
|
||||||
|
cycles = JZ4780_NEMC_NS_TO_TICKS(sc, val);
|
||||||
|
if (cycles > 31) {
|
||||||
|
device_printf(sc->dev,
|
||||||
|
"invalid value of %s %u (%u cycles), maximum %u cycles supported\n",
|
||||||
|
"ingenic,nemc-tAW", val, cycles, 15);
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
smcr &= ~JZ_NEMC_SMCR_TAW_MASK;
|
||||||
|
smcr |= ticks_to_tBP_tAW[cycles] << JZ_NEMC_SMCR_TAW_SHIFT;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (OF_getencprop(node, "ingenic,nemc-tSTRV", &val, sizeof(val)) > 0) {
|
||||||
|
cycles = JZ4780_NEMC_NS_TO_TICKS(sc, val);
|
||||||
|
if (cycles > 63) {
|
||||||
|
device_printf(sc->dev,
|
||||||
|
"invalid value of %s %u (%u cycles), maximum %u cycles supported\n",
|
||||||
|
"ingenic,nemc-tSTRV", val, cycles, 15);
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
smcr &= ~JZ_NEMC_SMCR_STRV_MASK;
|
||||||
|
smcr |= cycles << JZ_NEMC_SMCR_STRV_SHIFT;
|
||||||
|
}
|
||||||
|
CSR_WRITE_4(sc, JZ_NEMC_SMCR(bank), smcr);
|
||||||
|
sc->banks |= (1 << bank);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Wholesale copy of simplebus routine */
|
||||||
|
static int
|
||||||
|
jz4780_nemc_fill_ranges(phandle_t node, struct simplebus_softc *sc)
|
||||||
|
{
|
||||||
|
int host_address_cells;
|
||||||
|
cell_t *base_ranges;
|
||||||
|
ssize_t nbase_ranges;
|
||||||
|
int err;
|
||||||
|
int i, j, k;
|
||||||
|
|
||||||
|
err = OF_searchencprop(OF_parent(node), "#address-cells",
|
||||||
|
&host_address_cells, sizeof(host_address_cells));
|
||||||
|
if (err <= 0)
|
||||||
|
return (-1);
|
||||||
|
|
||||||
|
nbase_ranges = OF_getproplen(node, "ranges");
|
||||||
|
if (nbase_ranges < 0)
|
||||||
|
return (-1);
|
||||||
|
sc->nranges = nbase_ranges / sizeof(cell_t) /
|
||||||
|
(sc->acells + host_address_cells + sc->scells);
|
||||||
|
if (sc->nranges == 0)
|
||||||
|
return (0);
|
||||||
|
|
||||||
|
sc->ranges = malloc(sc->nranges * sizeof(sc->ranges[0]),
|
||||||
|
M_DEVBUF, M_WAITOK);
|
||||||
|
base_ranges = malloc(nbase_ranges, M_DEVBUF, M_WAITOK);
|
||||||
|
OF_getencprop(node, "ranges", base_ranges, nbase_ranges);
|
||||||
|
|
||||||
|
for (i = 0, j = 0; i < sc->nranges; i++) {
|
||||||
|
sc->ranges[i].bus = 0;
|
||||||
|
for (k = 0; k < sc->acells; k++) {
|
||||||
|
sc->ranges[i].bus <<= 32;
|
||||||
|
sc->ranges[i].bus |= base_ranges[j++];
|
||||||
|
}
|
||||||
|
sc->ranges[i].host = 0;
|
||||||
|
for (k = 0; k < host_address_cells; k++) {
|
||||||
|
sc->ranges[i].host <<= 32;
|
||||||
|
sc->ranges[i].host |= base_ranges[j++];
|
||||||
|
}
|
||||||
|
sc->ranges[i].size = 0;
|
||||||
|
for (k = 0; k < sc->scells; k++) {
|
||||||
|
sc->ranges[i].size <<= 32;
|
||||||
|
sc->ranges[i].size |= base_ranges[j++];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
free(base_ranges, M_DEVBUF);
|
||||||
|
return (sc->nranges);
|
||||||
|
}
|
||||||
|
|
||||||
|
static int
|
||||||
|
jz4780_nemc_attach(device_t dev)
|
||||||
|
{
|
||||||
|
struct jz4780_nemc_softc *sc = device_get_softc(dev);
|
||||||
|
phandle_t node;
|
||||||
|
uint64_t freq;
|
||||||
|
|
||||||
|
sc->dev = dev;
|
||||||
|
|
||||||
|
if (bus_alloc_resources(dev, jz4780_nemc_spec, sc->res)) {
|
||||||
|
device_printf(dev, "could not allocate resources for device\n");
|
||||||
|
return (ENXIO);
|
||||||
|
}
|
||||||
|
|
||||||
|
node = ofw_bus_get_node(dev);
|
||||||
|
|
||||||
|
/* Initialize simplebus and enumerate resources */
|
||||||
|
simplebus_init(dev, node);
|
||||||
|
|
||||||
|
if (jz4780_nemc_fill_ranges(node, &sc->simplebus_sc) < 0)
|
||||||
|
goto error;
|
||||||
|
|
||||||
|
/* Figure our underlying clock rate. */
|
||||||
|
if (clk_get_by_ofw_index(dev, 0, 0, &sc->clk) != 0) {
|
||||||
|
device_printf(dev, "could not lookup device clock\n");
|
||||||
|
goto error;
|
||||||
|
}
|
||||||
|
if (clk_enable(sc->clk) != 0) {
|
||||||
|
device_printf(dev, "could not enable device clock\n");
|
||||||
|
goto error;
|
||||||
|
}
|
||||||
|
if (clk_get_freq(sc->clk, &freq) != 0) {
|
||||||
|
device_printf(dev, "could not determine clock speed\n");
|
||||||
|
goto error;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Convert clock frequency to picoseconds-per-tick value. */
|
||||||
|
sc->clock_tick_psecs = (uint32_t)(1000000000000ULL / freq);
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Allow devices to identify.
|
||||||
|
*/
|
||||||
|
bus_generic_probe(dev);
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Now walk the 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:
|
||||||
|
jz4780_nemc_detach(dev);
|
||||||
|
return (ENXIO);
|
||||||
|
}
|
||||||
|
|
||||||
|
static int
|
||||||
|
jz4780_nemc_detach(device_t dev)
|
||||||
|
{
|
||||||
|
struct jz4780_nemc_softc *sc = device_get_softc(dev);
|
||||||
|
|
||||||
|
bus_generic_detach(dev);
|
||||||
|
if (sc->clk != NULL)
|
||||||
|
clk_release(sc->clk);
|
||||||
|
bus_release_resources(dev, jz4780_nemc_spec, sc->res);
|
||||||
|
return (0);
|
||||||
|
}
|
||||||
|
|
||||||
|
static int
|
||||||
|
jz4780_nemc_decode_bank(struct simplebus_softc *sc, struct resource *r,
|
||||||
|
u_int *bank)
|
||||||
|
{
|
||||||
|
rman_res_t start, end;
|
||||||
|
int i;
|
||||||
|
|
||||||
|
start = rman_get_start(r);
|
||||||
|
end = rman_get_end(r);
|
||||||
|
|
||||||
|
/* Remap through ranges property */
|
||||||
|
for (i = 0; i < sc->nranges; i++) {
|
||||||
|
if (start >= sc->ranges[i].host && end <
|
||||||
|
sc->ranges[i].host + sc->ranges[i].size) {
|
||||||
|
*bank = (sc->ranges[i].bus >> 32);
|
||||||
|
return (0);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return (1);
|
||||||
|
}
|
||||||
|
|
||||||
|
static int
|
||||||
|
jz4780_nemc_activate_resource(device_t bus, device_t child, int type, int rid,
|
||||||
|
struct resource *r)
|
||||||
|
{
|
||||||
|
struct jz4780_nemc_softc *sc;
|
||||||
|
u_int bank;
|
||||||
|
int err;
|
||||||
|
|
||||||
|
if (type == SYS_RES_MEMORY) {
|
||||||
|
sc = device_get_softc(bus);
|
||||||
|
|
||||||
|
/* Figure out on what bank device is residing */
|
||||||
|
err = jz4780_nemc_decode_bank(&sc->simplebus_sc, r, &bank);
|
||||||
|
if (err == 0) {
|
||||||
|
/* Attempt to configure the bank if not done already */
|
||||||
|
err = jz4780_nemc_configure_bank(sc, child, bank);
|
||||||
|
if (err != 0)
|
||||||
|
return (err);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Call default implementation to finish the work */
|
||||||
|
return (bus_generic_activate_resource(bus, child,
|
||||||
|
type, rid, r));
|
||||||
|
}
|
||||||
|
|
||||||
|
static device_method_t jz4780_nemc_methods[] = {
|
||||||
|
/* Device interface */
|
||||||
|
DEVMETHOD(device_probe, jz4780_nemc_probe),
|
||||||
|
DEVMETHOD(device_attach, jz4780_nemc_attach),
|
||||||
|
DEVMETHOD(device_detach, jz4780_nemc_detach),
|
||||||
|
|
||||||
|
/* Overrides to configure bank on resource activation */
|
||||||
|
DEVMETHOD(bus_activate_resource, jz4780_nemc_activate_resource),
|
||||||
|
|
||||||
|
DEVMETHOD_END
|
||||||
|
};
|
||||||
|
|
||||||
|
static devclass_t jz4780_nemc_devclass;
|
||||||
|
DEFINE_CLASS_1(nemc, jz4780_nemc_driver, jz4780_nemc_methods,
|
||||||
|
sizeof(struct jz4780_nemc_softc), simplebus_driver);
|
||||||
|
DRIVER_MODULE(jz4780_nemc, simplebus, jz4780_nemc_driver,
|
||||||
|
jz4780_nemc_devclass, 0, 0);
|
318
sys/mips/ingenic/jz4780_ohci.c
Normal file
318
sys/mips/ingenic/jz4780_ohci.c
Normal file
@ -0,0 +1,318 @@
|
|||||||
|
/*-
|
||||||
|
* Copyright (c) 2015, Alexander Kabaev <kan@FreeBSD.org>
|
||||||
|
* Copyright (c) 2009, Oleksandr Tymoshenko <gonzo@FreeBSD.org>
|
||||||
|
* All rights reserved.
|
||||||
|
*
|
||||||
|
* Redistribution and use in source and binary forms, with or without
|
||||||
|
* modification, are permitted provided that the following conditions
|
||||||
|
* are met:
|
||||||
|
* 1. Redistributions of source code must retain the above copyright
|
||||||
|
* notice unmodified, this list of conditions, and the following
|
||||||
|
* disclaimer.
|
||||||
|
* 2. Redistributions in binary form must reproduce the above copyright
|
||||||
|
* notice, this list of conditions and the following disclaimer in the
|
||||||
|
* documentation and/or other materials provided with the distribution.
|
||||||
|
*
|
||||||
|
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
|
||||||
|
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||||
|
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
||||||
|
* ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
|
||||||
|
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
|
||||||
|
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
|
||||||
|
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
|
||||||
|
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
|
||||||
|
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
|
||||||
|
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
|
||||||
|
* SUCH DAMAGE.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include <sys/cdefs.h>
|
||||||
|
__FBSDID("$FreeBSD$");
|
||||||
|
|
||||||
|
#include <sys/param.h>
|
||||||
|
#include <sys/systm.h>
|
||||||
|
#include <sys/bus.h>
|
||||||
|
#include <sys/rman.h>
|
||||||
|
#include <sys/condvar.h>
|
||||||
|
#include <sys/kernel.h>
|
||||||
|
#include <sys/module.h>
|
||||||
|
#include <sys/gpio.h>
|
||||||
|
|
||||||
|
#include <dev/extres/clk/clk.h>
|
||||||
|
|
||||||
|
#include <dev/usb/usb.h>
|
||||||
|
#include <dev/usb/usbdi.h>
|
||||||
|
|
||||||
|
#include <dev/usb/usb_core.h>
|
||||||
|
#include <dev/usb/usb_busdma.h>
|
||||||
|
#include <dev/usb/usb_process.h>
|
||||||
|
#include <dev/usb/usb_util.h>
|
||||||
|
|
||||||
|
#include <dev/usb/usb_controller.h>
|
||||||
|
#include <dev/usb/usb_bus.h>
|
||||||
|
#include <dev/usb/controller/ohci.h>
|
||||||
|
#include <dev/usb/controller/ohcireg.h>
|
||||||
|
|
||||||
|
#include <dev/ofw/ofw_bus.h>
|
||||||
|
#include <dev/ofw/ofw_bus_subr.h>
|
||||||
|
|
||||||
|
#include <dev/gpio/gpiobusvar.h>
|
||||||
|
|
||||||
|
#include <mips/ingenic/jz4780_clock.h>
|
||||||
|
#include <mips/ingenic/jz4780_regs.h>
|
||||||
|
|
||||||
|
static int jz4780_ohci_attach(device_t dev);
|
||||||
|
static int jz4780_ohci_detach(device_t dev);
|
||||||
|
static int jz4780_ohci_probe(device_t dev);
|
||||||
|
|
||||||
|
struct jz4780_ohci_softc
|
||||||
|
{
|
||||||
|
struct ohci_softc sc_ohci;
|
||||||
|
struct gpiobus_pin *gpio_vbus;
|
||||||
|
clk_t clk;
|
||||||
|
};
|
||||||
|
|
||||||
|
static int
|
||||||
|
jz4780_ohci_probe(device_t dev)
|
||||||
|
{
|
||||||
|
if (!ofw_bus_status_okay(dev))
|
||||||
|
return (ENXIO);
|
||||||
|
|
||||||
|
if (!ofw_bus_is_compatible(dev, "ingenic,jz4780-ohci"))
|
||||||
|
return (ENXIO);
|
||||||
|
|
||||||
|
device_set_desc(dev, "Ingenic JZ4780 OHCI");
|
||||||
|
|
||||||
|
return (BUS_PROBE_DEFAULT);
|
||||||
|
}
|
||||||
|
|
||||||
|
static int
|
||||||
|
jz4780_ohci_vbus_gpio_enable(device_t dev, struct jz4780_ohci_softc *sc)
|
||||||
|
{
|
||||||
|
struct gpiobus_pin *gpio_vbus;
|
||||||
|
int error;
|
||||||
|
|
||||||
|
error = ofw_gpiobus_parse_gpios(dev, "ingenic,vbus-gpio", &gpio_vbus);
|
||||||
|
/*
|
||||||
|
* The pin can be mapped already by other device. Assume it also has need
|
||||||
|
* activated and proceed happily.
|
||||||
|
*/
|
||||||
|
if (error <= 0)
|
||||||
|
return (0);
|
||||||
|
|
||||||
|
sc->gpio_vbus = gpio_vbus;
|
||||||
|
if (error > 1) {
|
||||||
|
device_printf(dev, "too many vbus gpios\n");
|
||||||
|
return (ENXIO);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (sc->gpio_vbus != NULL) {
|
||||||
|
error = GPIO_PIN_SET(sc->gpio_vbus->dev, sc->gpio_vbus->pin, 1);
|
||||||
|
if (error != 0) {
|
||||||
|
device_printf(dev, "Cannot configure GPIO pin %d on %s\n",
|
||||||
|
sc->gpio_vbus->pin, device_get_nameunit(sc->gpio_vbus->dev));
|
||||||
|
return (error);
|
||||||
|
}
|
||||||
|
|
||||||
|
error = GPIO_PIN_SETFLAGS(sc->gpio_vbus->dev, sc->gpio_vbus->pin,
|
||||||
|
GPIO_PIN_OUTPUT);
|
||||||
|
if (error != 0) {
|
||||||
|
device_printf(dev, "Cannot configure GPIO pin %d on %s\n",
|
||||||
|
sc->gpio_vbus->pin, device_get_nameunit(sc->gpio_vbus->dev));
|
||||||
|
return (error);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return (0);
|
||||||
|
}
|
||||||
|
|
||||||
|
static int
|
||||||
|
jz4780_ohci_clk_enable(device_t dev)
|
||||||
|
{
|
||||||
|
struct jz4780_ohci_softc *sc;
|
||||||
|
int err;
|
||||||
|
|
||||||
|
sc = device_get_softc(dev);
|
||||||
|
|
||||||
|
err = clk_get_by_ofw_index(dev, 0, 0, &sc->clk);
|
||||||
|
if (err != 0) {
|
||||||
|
device_printf(dev, "unable to lookup device clock\n");
|
||||||
|
return (err);
|
||||||
|
}
|
||||||
|
err = clk_enable(sc->clk);
|
||||||
|
if (err != 0) {
|
||||||
|
device_printf(dev, "unable to enable device clock\n");
|
||||||
|
return (err);
|
||||||
|
}
|
||||||
|
err = clk_set_freq(sc->clk, 48000000, 0);
|
||||||
|
if (err != 0) {
|
||||||
|
device_printf(dev, "unable to set device clock to 48 kHZ\n");
|
||||||
|
return (err);
|
||||||
|
}
|
||||||
|
return (0);
|
||||||
|
}
|
||||||
|
|
||||||
|
static int
|
||||||
|
jz4780_ohci_attach(device_t dev)
|
||||||
|
{
|
||||||
|
struct jz4780_ohci_softc *sc = device_get_softc(dev);
|
||||||
|
int err;
|
||||||
|
int rid;
|
||||||
|
|
||||||
|
/* initialize some bus fields */
|
||||||
|
sc->sc_ohci.sc_bus.parent = dev;
|
||||||
|
sc->sc_ohci.sc_bus.devices = sc->sc_ohci.sc_devices;
|
||||||
|
sc->sc_ohci.sc_bus.devices_max = OHCI_MAX_DEVICES;
|
||||||
|
sc->sc_ohci.sc_bus.dma_bits = 32;
|
||||||
|
|
||||||
|
/* get all DMA memory */
|
||||||
|
if (usb_bus_mem_alloc_all(&sc->sc_ohci.sc_bus,
|
||||||
|
USB_GET_DMA_TAG(dev), &ohci_iterate_hw_softc)) {
|
||||||
|
return (ENOMEM);
|
||||||
|
}
|
||||||
|
|
||||||
|
sc->sc_ohci.sc_dev = dev;
|
||||||
|
|
||||||
|
/* frob vbus gpio */
|
||||||
|
err = jz4780_ohci_vbus_gpio_enable(dev, sc);
|
||||||
|
if (err)
|
||||||
|
goto error;
|
||||||
|
|
||||||
|
err = jz4780_ohci_clk_enable(dev);
|
||||||
|
if (err)
|
||||||
|
goto error;
|
||||||
|
|
||||||
|
rid = 0;
|
||||||
|
sc->sc_ohci.sc_io_res = bus_alloc_resource_any(dev, SYS_RES_MEMORY, &rid,
|
||||||
|
RF_ACTIVE);
|
||||||
|
if (sc->sc_ohci.sc_io_res == NULL) {
|
||||||
|
err = ENOMEM;
|
||||||
|
goto error;
|
||||||
|
}
|
||||||
|
sc->sc_ohci.sc_io_tag = rman_get_bustag(sc->sc_ohci.sc_io_res);
|
||||||
|
sc->sc_ohci.sc_io_hdl = rman_get_bushandle(sc->sc_ohci.sc_io_res);
|
||||||
|
sc->sc_ohci.sc_io_size = rman_get_size(sc->sc_ohci.sc_io_res);
|
||||||
|
|
||||||
|
rid = 0;
|
||||||
|
sc->sc_ohci.sc_irq_res = bus_alloc_resource_any(dev, SYS_RES_IRQ, &rid,
|
||||||
|
RF_ACTIVE);
|
||||||
|
if (sc->sc_ohci.sc_irq_res == NULL) {
|
||||||
|
err = ENOMEM;
|
||||||
|
goto error;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (jz4780_ohci_enable() != 0) {
|
||||||
|
device_printf(dev, "CGU failed to enable OHCI\n");
|
||||||
|
err = ENXIO;
|
||||||
|
goto error;
|
||||||
|
}
|
||||||
|
|
||||||
|
sc->sc_ohci.sc_bus.bdev = device_add_child(dev, "usbus", -1);
|
||||||
|
if (sc->sc_ohci.sc_bus.bdev == NULL) {
|
||||||
|
err = ENOMEM;
|
||||||
|
goto error;
|
||||||
|
}
|
||||||
|
device_set_ivars(sc->sc_ohci.sc_bus.bdev, &sc->sc_ohci.sc_bus);
|
||||||
|
|
||||||
|
err = bus_setup_intr(dev, sc->sc_ohci.sc_irq_res,
|
||||||
|
INTR_TYPE_BIO | INTR_MPSAFE, NULL,
|
||||||
|
(driver_intr_t *)ohci_interrupt, sc, &sc->sc_ohci.sc_intr_hdl);
|
||||||
|
if (err) {
|
||||||
|
err = ENXIO;
|
||||||
|
goto error;
|
||||||
|
}
|
||||||
|
|
||||||
|
strlcpy(sc->sc_ohci.sc_vendor, "Ingenic", sizeof(sc->sc_ohci.sc_vendor));
|
||||||
|
bus_space_write_4(sc->sc_ohci.sc_io_tag, sc->sc_ohci.sc_io_hdl, OHCI_CONTROL, 0);
|
||||||
|
|
||||||
|
err = ohci_init(&sc->sc_ohci);
|
||||||
|
if (!err)
|
||||||
|
err = device_probe_and_attach(sc->sc_ohci.sc_bus.bdev);
|
||||||
|
|
||||||
|
if (err)
|
||||||
|
goto error;
|
||||||
|
return (0);
|
||||||
|
|
||||||
|
error:
|
||||||
|
if (err)
|
||||||
|
jz4780_ohci_detach(dev);
|
||||||
|
return (err);
|
||||||
|
}
|
||||||
|
|
||||||
|
static int
|
||||||
|
jz4780_ohci_detach(device_t dev)
|
||||||
|
{
|
||||||
|
struct jz4780_ohci_softc *sc = device_get_softc(dev);
|
||||||
|
device_t bdev;
|
||||||
|
|
||||||
|
if (sc->sc_ohci.sc_bus.bdev) {
|
||||||
|
bdev = sc->sc_ohci.sc_bus.bdev;
|
||||||
|
device_detach(bdev);
|
||||||
|
device_delete_child(dev, bdev);
|
||||||
|
}
|
||||||
|
/* during module unload there are lots of children leftover */
|
||||||
|
device_delete_children(dev);
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Put the controller into reset, then disable clocks and do
|
||||||
|
* the MI tear down. We have to disable the clocks/hardware
|
||||||
|
* after we do the rest of the teardown. We also disable the
|
||||||
|
* clocks in the opposite order we acquire them, but that
|
||||||
|
* doesn't seem to be absolutely necessary. We free up the
|
||||||
|
* clocks after we disable them, so the system could, in
|
||||||
|
* theory, reuse them.
|
||||||
|
*/
|
||||||
|
if (sc->sc_ohci.sc_io_res != NULL) {
|
||||||
|
bus_space_write_4(sc->sc_ohci.sc_io_tag, sc->sc_ohci.sc_io_hdl,
|
||||||
|
OHCI_CONTROL, 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (sc->sc_ohci.sc_intr_hdl) {
|
||||||
|
bus_teardown_intr(dev, sc->sc_ohci.sc_irq_res, sc->sc_ohci.sc_intr_hdl);
|
||||||
|
sc->sc_ohci.sc_intr_hdl = NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (sc->sc_ohci.sc_irq_res && sc->sc_ohci.sc_intr_hdl) {
|
||||||
|
/*
|
||||||
|
* only call ohci_detach() after ohci_init()
|
||||||
|
*/
|
||||||
|
ohci_detach(&sc->sc_ohci);
|
||||||
|
|
||||||
|
bus_release_resource(dev, SYS_RES_IRQ, 0, sc->sc_ohci.sc_irq_res);
|
||||||
|
sc->sc_ohci.sc_irq_res = NULL;
|
||||||
|
}
|
||||||
|
if (sc->sc_ohci.sc_io_res) {
|
||||||
|
bus_release_resource(dev, SYS_RES_MEMORY, 0, sc->sc_ohci.sc_io_res);
|
||||||
|
sc->sc_ohci.sc_io_res = NULL;
|
||||||
|
sc->sc_ohci.sc_io_tag = 0;
|
||||||
|
sc->sc_ohci.sc_io_hdl = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (sc->clk != NULL)
|
||||||
|
clk_release(sc->clk);
|
||||||
|
|
||||||
|
usb_bus_mem_free_all(&sc->sc_ohci.sc_bus, &ohci_iterate_hw_softc);
|
||||||
|
free(sc->gpio_vbus, M_DEVBUF);
|
||||||
|
return (0);
|
||||||
|
}
|
||||||
|
|
||||||
|
static device_method_t ohci_methods[] = {
|
||||||
|
/* Device interface */
|
||||||
|
DEVMETHOD(device_probe, jz4780_ohci_probe),
|
||||||
|
DEVMETHOD(device_attach, jz4780_ohci_attach),
|
||||||
|
DEVMETHOD(device_detach, jz4780_ohci_detach),
|
||||||
|
DEVMETHOD(device_suspend, bus_generic_suspend),
|
||||||
|
DEVMETHOD(device_resume, bus_generic_resume),
|
||||||
|
DEVMETHOD(device_shutdown, bus_generic_shutdown),
|
||||||
|
|
||||||
|
DEVMETHOD_END
|
||||||
|
};
|
||||||
|
|
||||||
|
static driver_t ohci_driver = {
|
||||||
|
.name = "ohci",
|
||||||
|
.methods = ohci_methods,
|
||||||
|
.size = sizeof(struct jz4780_ohci_softc),
|
||||||
|
};
|
||||||
|
|
||||||
|
static devclass_t ohci_devclass;
|
||||||
|
|
||||||
|
DRIVER_MODULE(ohci, simplebus, ohci_driver, ohci_devclass, 0, 0);
|
260
sys/mips/ingenic/jz4780_pinctrl.c
Normal file
260
sys/mips/ingenic/jz4780_pinctrl.c
Normal file
@ -0,0 +1,260 @@
|
|||||||
|
/*-
|
||||||
|
* Copyright 2015 Alexander Kabaev <kan@FreeBSD.org>
|
||||||
|
* All rights reserved.
|
||||||
|
*
|
||||||
|
* Redistribution and use in source and binary forms, with or without
|
||||||
|
* modification, are permitted provided that the following conditions
|
||||||
|
* are met:
|
||||||
|
* 1. Redistributions of source code must retain the above copyright
|
||||||
|
* notice, this list of conditions and the following disclaimer.
|
||||||
|
* 2. Redistributions in binary form must reproduce the above copyright
|
||||||
|
* notice, this list of conditions and the following disclaimer in the
|
||||||
|
* documentation and/or other materials provided with the distribution.
|
||||||
|
*
|
||||||
|
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
|
||||||
|
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||||
|
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
||||||
|
* ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
|
||||||
|
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
|
||||||
|
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
|
||||||
|
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
|
||||||
|
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
|
||||||
|
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
|
||||||
|
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
|
||||||
|
* SUCH DAMAGE.
|
||||||
|
*/
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Ingenic JZ4780 pinctrl driver.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include <sys/cdefs.h>
|
||||||
|
__FBSDID("$FreeBSD$");
|
||||||
|
|
||||||
|
#include <sys/param.h>
|
||||||
|
#include <sys/systm.h>
|
||||||
|
#include <sys/conf.h>
|
||||||
|
#include <sys/bus.h>
|
||||||
|
#include <sys/gpio.h>
|
||||||
|
#include <sys/kernel.h>
|
||||||
|
#include <sys/module.h>
|
||||||
|
#include <sys/lock.h>
|
||||||
|
#include <sys/mutex.h>
|
||||||
|
#include <sys/queue.h>
|
||||||
|
#include <sys/resource.h>
|
||||||
|
#include <sys/rman.h>
|
||||||
|
|
||||||
|
#include <machine/bus.h>
|
||||||
|
|
||||||
|
#include <dev/ofw/ofw_bus.h>
|
||||||
|
#include <dev/ofw/ofw_bus_subr.h>
|
||||||
|
|
||||||
|
#include <dev/fdt/fdt_common.h>
|
||||||
|
#include <dev/fdt/fdt_pinctrl.h>
|
||||||
|
#include <dev/fdt/simplebus.h>
|
||||||
|
|
||||||
|
#include <mips/ingenic/jz4780_regs.h>
|
||||||
|
|
||||||
|
#include "jz4780_gpio_if.h"
|
||||||
|
|
||||||
|
struct jz4780_pinctrl_softc {
|
||||||
|
struct simplebus_softc ssc;
|
||||||
|
device_t dev;
|
||||||
|
};
|
||||||
|
|
||||||
|
#define CHIP_REG_STRIDE 256
|
||||||
|
#define CHIP_REG_OFFSET(base, chip) ((base) + (chip) * CHIP_REG_STRIDE)
|
||||||
|
|
||||||
|
static int
|
||||||
|
jz4780_pinctrl_probe(device_t dev)
|
||||||
|
{
|
||||||
|
|
||||||
|
if (!ofw_bus_status_okay(dev))
|
||||||
|
return (ENXIO);
|
||||||
|
|
||||||
|
if (!ofw_bus_is_compatible(dev, "ingenic,jz4780-pinctrl"))
|
||||||
|
return (ENXIO);
|
||||||
|
|
||||||
|
device_set_desc(dev, "Ingenic JZ4780 GPIO");
|
||||||
|
|
||||||
|
return (BUS_PROBE_DEFAULT);
|
||||||
|
}
|
||||||
|
|
||||||
|
static int
|
||||||
|
jz4780_pinctrl_attach(device_t dev)
|
||||||
|
{
|
||||||
|
struct jz4780_pinctrl_softc *sc;
|
||||||
|
struct resource_list *rs;
|
||||||
|
struct resource_list_entry *re;
|
||||||
|
phandle_t dt_parent, dt_child;
|
||||||
|
int i, ret;
|
||||||
|
|
||||||
|
sc = device_get_softc(dev);
|
||||||
|
sc->dev = dev;
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Fetch our own resource list to dole memory between children
|
||||||
|
*/
|
||||||
|
rs = BUS_GET_RESOURCE_LIST(device_get_parent(dev), dev);
|
||||||
|
if (rs == NULL)
|
||||||
|
return (ENXIO);
|
||||||
|
re = resource_list_find(rs, SYS_RES_MEMORY, 0);
|
||||||
|
if (re == NULL)
|
||||||
|
return (ENXIO);
|
||||||
|
|
||||||
|
simplebus_init(dev, 0);
|
||||||
|
|
||||||
|
/* Iterate over this node children, looking for pin controllers */
|
||||||
|
dt_parent = ofw_bus_get_node(dev);
|
||||||
|
i = 0;
|
||||||
|
for (dt_child = OF_child(dt_parent); dt_child != 0;
|
||||||
|
dt_child = OF_peer(dt_child)) {
|
||||||
|
struct simplebus_devinfo *ndi;
|
||||||
|
device_t child;
|
||||||
|
bus_addr_t phys;
|
||||||
|
bus_size_t size;
|
||||||
|
|
||||||
|
/* Add gpio controller child */
|
||||||
|
if (!OF_hasprop(dt_child, "gpio-controller"))
|
||||||
|
continue;
|
||||||
|
child = simplebus_add_device(dev, dt_child, 0, NULL, -1, NULL);
|
||||||
|
if (child == NULL)
|
||||||
|
break;
|
||||||
|
/* Setup child resources */
|
||||||
|
phys = CHIP_REG_OFFSET(re->start, i);
|
||||||
|
size = CHIP_REG_STRIDE;
|
||||||
|
if (phys + size - 1 <= re->end) {
|
||||||
|
ndi = device_get_ivars(child);
|
||||||
|
resource_list_add(&ndi->rl, SYS_RES_MEMORY, 0,
|
||||||
|
phys, phys + size - 1, size);
|
||||||
|
}
|
||||||
|
i++;
|
||||||
|
}
|
||||||
|
|
||||||
|
ret = bus_generic_attach(dev);
|
||||||
|
if (ret == 0) {
|
||||||
|
fdt_pinctrl_register(dev, "ingenic,pins");
|
||||||
|
fdt_pinctrl_configure_tree(dev);
|
||||||
|
}
|
||||||
|
return (ret);
|
||||||
|
}
|
||||||
|
|
||||||
|
static int
|
||||||
|
jz4780_pinctrl_detach(device_t dev)
|
||||||
|
{
|
||||||
|
|
||||||
|
bus_generic_detach(dev);
|
||||||
|
return (0);
|
||||||
|
}
|
||||||
|
|
||||||
|
struct jx4780_bias_prop {
|
||||||
|
const char *name;
|
||||||
|
uint32_t bias;
|
||||||
|
};
|
||||||
|
|
||||||
|
static struct jx4780_bias_prop jx4780_bias_table[] = {
|
||||||
|
{ "bias-disable", 0 },
|
||||||
|
{ "bias-pull-up", GPIO_PIN_PULLUP },
|
||||||
|
{ "bias-pull-down", GPIO_PIN_PULLDOWN },
|
||||||
|
};
|
||||||
|
|
||||||
|
static int
|
||||||
|
jz4780_pinctrl_parse_pincfg(phandle_t pincfgxref, uint32_t *bias_value)
|
||||||
|
{
|
||||||
|
phandle_t pincfg_node;
|
||||||
|
int i;
|
||||||
|
|
||||||
|
pincfg_node = OF_node_from_xref(pincfgxref);
|
||||||
|
for (i = 0; i < nitems(jx4780_bias_table); i++) {
|
||||||
|
if (OF_hasprop(pincfg_node, jx4780_bias_table[i].name)) {
|
||||||
|
*bias_value = jx4780_bias_table[i].bias;
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
static device_t
|
||||||
|
jz4780_pinctrl_chip_lookup(struct jz4780_pinctrl_softc *sc, phandle_t chipxref)
|
||||||
|
{
|
||||||
|
device_t chipdev;
|
||||||
|
|
||||||
|
chipdev = OF_device_from_xref(chipxref);
|
||||||
|
return chipdev;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int
|
||||||
|
jz4780_pinctrl_configure_pins(device_t dev, phandle_t cfgxref)
|
||||||
|
{
|
||||||
|
struct jz4780_pinctrl_softc *sc = device_get_softc(dev);
|
||||||
|
device_t chip;
|
||||||
|
phandle_t node;
|
||||||
|
ssize_t i, len;
|
||||||
|
uint32_t *value, *pconf;
|
||||||
|
int result;
|
||||||
|
|
||||||
|
node = OF_node_from_xref(cfgxref);
|
||||||
|
|
||||||
|
len = OF_getencprop_alloc(node, "ingenic,pins", sizeof(uint32_t) * 4,
|
||||||
|
(void **)&value);
|
||||||
|
if (len < 0) {
|
||||||
|
device_printf(dev,
|
||||||
|
"missing ingenic,pins attribute in FDT\n");
|
||||||
|
return (ENXIO);
|
||||||
|
}
|
||||||
|
|
||||||
|
pconf = value;
|
||||||
|
result = EINVAL;
|
||||||
|
for (i = 0; i < len; i++, pconf += 4) {
|
||||||
|
uint32_t bias;
|
||||||
|
|
||||||
|
/* Lookup the chip that handles this configuration */
|
||||||
|
chip = jz4780_pinctrl_chip_lookup(sc, pconf[0]);
|
||||||
|
if (chip == NULL) {
|
||||||
|
device_printf(dev,
|
||||||
|
"invalid gpio controller reference in FDT\n");
|
||||||
|
goto done;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (jz4780_pinctrl_parse_pincfg(pconf[3], &bias) != 0) {
|
||||||
|
device_printf(dev,
|
||||||
|
"invalid pin bias for pin %u on %s in FDT\n",
|
||||||
|
pconf[1], ofw_bus_get_name(chip));
|
||||||
|
goto done;
|
||||||
|
}
|
||||||
|
|
||||||
|
result = JZ4780_GPIO_CONFIGURE_PIN(chip, pconf[1], pconf[2],
|
||||||
|
bias);
|
||||||
|
if (result != 0) {
|
||||||
|
device_printf(dev,
|
||||||
|
"failed to configure pin %u on %s\n", pconf[1],
|
||||||
|
ofw_bus_get_name(chip));
|
||||||
|
goto done;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
result = 0;
|
||||||
|
done:
|
||||||
|
free(value, M_OFWPROP);
|
||||||
|
return (result);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
static device_method_t jz4780_pinctrl_methods[] = {
|
||||||
|
/* Device interface */
|
||||||
|
DEVMETHOD(device_probe, jz4780_pinctrl_probe),
|
||||||
|
DEVMETHOD(device_attach, jz4780_pinctrl_attach),
|
||||||
|
DEVMETHOD(device_detach, jz4780_pinctrl_detach),
|
||||||
|
|
||||||
|
/* fdt_pinctrl interface */
|
||||||
|
DEVMETHOD(fdt_pinctrl_configure, jz4780_pinctrl_configure_pins),
|
||||||
|
|
||||||
|
DEVMETHOD_END
|
||||||
|
};
|
||||||
|
|
||||||
|
static devclass_t jz4780_pinctrl_devclass;
|
||||||
|
DEFINE_CLASS_1(pinctrl, jz4780_pinctrl_driver, jz4780_pinctrl_methods,
|
||||||
|
sizeof(struct jz4780_pinctrl_softc), simplebus_driver);
|
||||||
|
EARLY_DRIVER_MODULE(pinctrl, simplebus, jz4780_pinctrl_driver,
|
||||||
|
jz4780_pinctrl_devclass, 0, 0, BUS_PASS_INTERRUPT + BUS_PASS_ORDER_LATE);
|
33
sys/mips/ingenic/jz4780_pinctrl.h
Normal file
33
sys/mips/ingenic/jz4780_pinctrl.h
Normal file
@ -0,0 +1,33 @@
|
|||||||
|
/*-
|
||||||
|
* Copyright 2015 Alexander Kabaev <kan@FreeBSD.org>
|
||||||
|
* All rights reserved.
|
||||||
|
*
|
||||||
|
* Redistribution and use in source and binary forms, with or without
|
||||||
|
* modification, are permitted provided that the following conditions
|
||||||
|
* are met:
|
||||||
|
* 1. Redistributions of source code must retain the above copyright
|
||||||
|
* notice, this list of conditions and the following disclaimer.
|
||||||
|
* 2. Redistributions in binary form must reproduce the above copyright
|
||||||
|
* notice, this list of conditions and the following disclaimer in the
|
||||||
|
* documentation and/or other materials provided with the distribution.
|
||||||
|
*
|
||||||
|
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
|
||||||
|
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||||
|
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
||||||
|
* ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
|
||||||
|
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
|
||||||
|
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
|
||||||
|
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
|
||||||
|
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
|
||||||
|
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
|
||||||
|
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
|
||||||
|
* SUCH DAMAGE.
|
||||||
|
*
|
||||||
|
* $FreeBSD$
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef _MIPS_INGENIC_JZ4780_PINCTRL_H
|
||||||
|
#define _MIPS_INGENIC_JZ4780_PINCTRL_H
|
||||||
|
|
||||||
|
|
||||||
|
#endif /* _MIPS_INGENIC_JZ4780_PINCTRL_H */
|
787
sys/mips/ingenic/jz4780_regs.h
Normal file
787
sys/mips/ingenic/jz4780_regs.h
Normal file
@ -0,0 +1,787 @@
|
|||||||
|
/* $NetBSD: ingenic_regs.h,v 1.22 2015/10/08 17:54:30 macallan Exp $ */
|
||||||
|
|
||||||
|
/*-
|
||||||
|
* Copyright (c) 2014 Michael Lorenz
|
||||||
|
* All rights reserved.
|
||||||
|
*
|
||||||
|
* Redistribution and use in source and binary forms, with or without
|
||||||
|
* modification, are permitted provided that the following conditions
|
||||||
|
* are met:
|
||||||
|
* 1. Redistributions of source code must retain the above copyright
|
||||||
|
* notice, this list of conditions and the following disclaimer.
|
||||||
|
* 2. Redistributions in binary form must reproduce the above copyright
|
||||||
|
* notice, this list of conditions and the following disclaimer in the
|
||||||
|
* documentation and/or other materials provided with the distribution.
|
||||||
|
*
|
||||||
|
* THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
|
||||||
|
* ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
|
||||||
|
* TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
|
||||||
|
* PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
|
||||||
|
* BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
|
||||||
|
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
|
||||||
|
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
|
||||||
|
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
|
||||||
|
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
|
||||||
|
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
|
||||||
|
* POSSIBILITY OF SUCH DAMAGE.
|
||||||
|
*
|
||||||
|
* $FreeBSD$
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef JZ4780_REGS_H
|
||||||
|
#define JZ4780_REGS_H
|
||||||
|
|
||||||
|
/* for mips_wbflush() */
|
||||||
|
#include <machine/locore.h>
|
||||||
|
|
||||||
|
/* UARTs, mostly 16550 compatible with 32bit spaced registers */
|
||||||
|
#define JZ_UART0 0x10030000
|
||||||
|
#define JZ_UART1 0x10031000
|
||||||
|
#define JZ_UART2 0x10032000
|
||||||
|
#define JZ_UART3 0x10033000
|
||||||
|
#define JZ_UART4 0x10034000
|
||||||
|
|
||||||
|
/* LCD controller base addresses, registers are in jzfb_regs.h */
|
||||||
|
#define JZ_LCDC0_BASE 0x13050000
|
||||||
|
#define JZ_LCDC1_BASE 0x130a0000
|
||||||
|
|
||||||
|
/* TCU unit base address */
|
||||||
|
#define JZ_TCU_BASE 0x10002000
|
||||||
|
|
||||||
|
/* Watchdog */
|
||||||
|
#define JZ_WDOG_TDR 0x00000000 /* compare */
|
||||||
|
#define JZ_WDOG_TCER 0x00000004
|
||||||
|
#define TCER_ENABLE 0x01 /* enable counter */
|
||||||
|
#define JZ_WDOG_TCNT 0x00000008 /* 16bit up count */
|
||||||
|
#define JZ_WDOG_TCSR 0x0000000c
|
||||||
|
#define TCSR_PCK_EN 0x01 /* PCLK */
|
||||||
|
#define TCSR_RTC_EN 0x02 /* RTCCLK - 32.768kHz */
|
||||||
|
#define TCSR_EXT_EN 0x04 /* EXTCLK - 48MHz */
|
||||||
|
#define TCSR_PRESCALE_M 0x38
|
||||||
|
#define TCSR_DIV_1 0x00
|
||||||
|
#define TCSR_DIV_4 0x08
|
||||||
|
#define TCSR_DIV_16 0x10
|
||||||
|
#define TCSR_DIV_64 0x18
|
||||||
|
#define TCSR_DIV_256 0x20
|
||||||
|
#define TCSR_DIV_1024 0x28
|
||||||
|
|
||||||
|
/* timers and PWMs */
|
||||||
|
#define JZ_TC_TER 0x00000010 /* TC enable reg, ro */
|
||||||
|
#define JZ_TC_TESR 0x00000014 /* TC enable set reg. */
|
||||||
|
#define TESR_TCST0 0x0001 /* enable counter 0 */
|
||||||
|
#define TESR_TCST1 0x0002 /* enable counter 1 */
|
||||||
|
#define TESR_TCST2 0x0004 /* enable counter 2 */
|
||||||
|
#define TESR_TCST3 0x0008 /* enable counter 3 */
|
||||||
|
#define TESR_TCST4 0x0010 /* enable counter 4 */
|
||||||
|
#define TESR_TCST5 0x0020 /* enable counter 5 */
|
||||||
|
#define TESR_TCST6 0x0040 /* enable counter 6 */
|
||||||
|
#define TESR_TCST7 0x0080 /* enable counter 7 */
|
||||||
|
#define TESR_OST 0x8000 /* enable OST */
|
||||||
|
#define JZ_TC_TECR 0x00000018 /* TC enable clear reg. */
|
||||||
|
#define JZ_TC_TFR 0x00000020
|
||||||
|
#define TFR_FFLAG0 0x00000001 /* channel 0 */
|
||||||
|
#define TFR_FFLAG1 0x00000002 /* channel 1 */
|
||||||
|
#define TFR_FFLAG2 0x00000004 /* channel 2 */
|
||||||
|
#define TFR_FFLAG3 0x00000008 /* channel 3 */
|
||||||
|
#define TFR_FFLAG4 0x00000010 /* channel 4 */
|
||||||
|
#define TFR_FFLAG5 0x00000020 /* channel 5 */
|
||||||
|
#define TFR_FFLAG6 0x00000040 /* channel 6 */
|
||||||
|
#define TFR_FFLAG7 0x00000080 /* channel 7 */
|
||||||
|
#define TFR_OSTFLAG 0x00008000 /* OS timer */
|
||||||
|
#define JZ_TC_TFSR 0x00000024 /* timer flag set */
|
||||||
|
#define JZ_TC_TFCR 0x00000028 /* timer flag clear */
|
||||||
|
#define JZ_TC_TMR 0x00000030 /* timer flag mask */
|
||||||
|
#define TMR_FMASK(n) (1 << (n))
|
||||||
|
#define TMR_HMASK(n) (1 << ((n) + 16))
|
||||||
|
#define JZ_TC_TMSR 0x00000034 /* timer flag mask set */
|
||||||
|
#define JZ_TC_TMCR 0x00000038 /* timer flag mask clear*/
|
||||||
|
|
||||||
|
#define JZ_TC_TDFR(n) (0x00000040 + (n * 0x10)) /* FULL compare */
|
||||||
|
#define JZ_TC_TDHR(n) (0x00000044 + (n * 0x10)) /* HALF compare */
|
||||||
|
#define JZ_TC_TCNT(n) (0x00000048 + (n * 0x10)) /* count */
|
||||||
|
|
||||||
|
#define JZ_TC_TCSR(n) (0x0000004c + (n * 0x10))
|
||||||
|
/* same bits as in JZ_WDOG_TCSR */
|
||||||
|
|
||||||
|
/* operating system timer */
|
||||||
|
#define JZ_OST_DATA 0x000000e0 /* compare */
|
||||||
|
#define JZ_OST_CNT_LO 0x000000e4
|
||||||
|
#define JZ_OST_CNT_HI 0x000000e8
|
||||||
|
#define JZ_OST_CTRL 0x000000ec
|
||||||
|
#define OSTC_PCK_EN 0x0001 /* use PCLK */
|
||||||
|
#define OSTC_RTC_EN 0x0002 /* use RTCCLK */
|
||||||
|
#define OSTC_EXT_EN 0x0004 /* use EXTCLK */
|
||||||
|
#define OSTC_PRESCALE_M 0x0038
|
||||||
|
#define OSTC_DIV_1 0x0000
|
||||||
|
#define OSTC_DIV_4 0x0008
|
||||||
|
#define OSTC_DIV_16 0x0010
|
||||||
|
#define OSTC_DIV_64 0x0018
|
||||||
|
#define OSTC_DIV_256 0x0020
|
||||||
|
#define OSTC_DIV_1024 0x0028
|
||||||
|
#define OSTC_SHUTDOWN 0x0200
|
||||||
|
#define OSTC_MODE 0x8000 /* 0 - reset to 0 when = OST_DATA */
|
||||||
|
#define JZ_OST_CNT_U32 0x000000fc /* copy of CNT_HI when reading CNT_LO */
|
||||||
|
|
||||||
|
static inline void
|
||||||
|
writereg(uint32_t reg, uint32_t val)
|
||||||
|
{
|
||||||
|
*(volatile int32_t *)MIPS_PHYS_TO_KSEG1(reg) = val;
|
||||||
|
mips_wbflush();
|
||||||
|
}
|
||||||
|
|
||||||
|
static inline uint32_t
|
||||||
|
readreg(uint32_t reg)
|
||||||
|
{
|
||||||
|
mips_wbflush();
|
||||||
|
return *(volatile int32_t *)MIPS_PHYS_TO_KSEG1(reg);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Clock management */
|
||||||
|
#define JZ_CGU_BASE 0x10000000
|
||||||
|
|
||||||
|
#define JZ_CPCCR 0x00000000 /* Clock Control Register */
|
||||||
|
#define JZ_PDIV_M 0x000f0000 /* PCLK divider mask */
|
||||||
|
#define JZ_PDIV_S 16 /* PCLK divider shift */
|
||||||
|
#define JZ_CDIV_M 0x0000000f /* CPU clock divider mask */
|
||||||
|
#define JZ_CDIV_S 0 /* CPU clock divider shift */
|
||||||
|
#define JZ_CPAPCR 0x00000010 /* APLL */
|
||||||
|
#define JZ_CPMPCR 0x00000014 /* MPLL */
|
||||||
|
#define JZ_CPEPCR 0x00000018 /* EPLL */
|
||||||
|
#define JZ_CPVPCR 0x0000001C /* VPLL */
|
||||||
|
#define JZ_PLLM_S 19 /* PLL multiplier shift */
|
||||||
|
#define JZ_PLLM_M 0xfff80000 /* PLL multiplier mask */
|
||||||
|
#define JZ_PLLN_S 13 /* PLL divider shift */
|
||||||
|
#define JZ_PLLN_M 0x0007e000 /* PLL divider mask */
|
||||||
|
#define JZ_PLLP_S 9 /* PLL postdivider shift */
|
||||||
|
#define JZ_PLLP_M 0x00001700 /* PLL postdivider mask */
|
||||||
|
#define JZ_PLLON 0x00000010 /* PLL is on and stable */
|
||||||
|
#define JZ_PLLBP 0x00000002 /* PLL bypass */
|
||||||
|
#define JZ_PLLEN 0x00000001 /* PLL enable */
|
||||||
|
#define JZ_CLKGR0 0x00000020 /* Clock Gating Registers */
|
||||||
|
#define CLK_NEMC (1 << 0)
|
||||||
|
#define CLK_BCH (1 << 1)
|
||||||
|
#define CLK_OTG0 (1 << 2)
|
||||||
|
#define CLK_MSC0 (1 << 3)
|
||||||
|
#define CLK_SSI0 (1 << 4)
|
||||||
|
#define CLK_SMB0 (1 << 5)
|
||||||
|
#define CLK_SMB1 (1 << 6)
|
||||||
|
#define CLK_SCC (1 << 7)
|
||||||
|
#define CLK_AIC (1 << 8)
|
||||||
|
#define CLK_TSSI0 (1 << 9)
|
||||||
|
#define CLK_OWI (1 << 10)
|
||||||
|
#define CLK_MSC1 (1 << 11)
|
||||||
|
#define CLK_MSC2 (1 << 12)
|
||||||
|
#define CLK_KBC (1 << 13)
|
||||||
|
#define CLK_SADC (1 << 14)
|
||||||
|
#define CLK_UART0 (1 << 15)
|
||||||
|
#define CLK_UART1 (1 << 16)
|
||||||
|
#define CLK_UART2 (1 << 17)
|
||||||
|
#define CLK_UART3 (1 << 18)
|
||||||
|
#define CLK_SSI1 (1 << 19)
|
||||||
|
#define CLK_SSI2 (1 << 20)
|
||||||
|
#define CLK_PDMA (1 << 21)
|
||||||
|
#define CLK_GPS (1 << 22)
|
||||||
|
#define CLK_MAC (1 << 23)
|
||||||
|
#define CLK_UHC (1 << 24)
|
||||||
|
#define CLK_SMB2 (1 << 25)
|
||||||
|
#define CLK_CIM (1 << 26)
|
||||||
|
#define CLK_TVE (1 << 27)
|
||||||
|
#define CLK_LCD (1 << 28)
|
||||||
|
#define CLK_IPU (1 << 29)
|
||||||
|
#define CLK_DDR0 (1 << 30)
|
||||||
|
#define CLK_DDR1 (1 << 31)
|
||||||
|
#define JZ_CLKGR1 0x00000028 /* Clock Gating Registers */
|
||||||
|
#define CLK_SMB3 (1 << 0)
|
||||||
|
#define CLK_TSSI1 (1 << 1)
|
||||||
|
#define CLK_VPU (1 << 2)
|
||||||
|
#define CLK_PCM (1 << 3)
|
||||||
|
#define CLK_GPU (1 << 4)
|
||||||
|
#define CLK_COMPRESS (1 << 5)
|
||||||
|
#define CLK_AIC1 (1 << 6)
|
||||||
|
#define CLK_GPVLC (1 << 7)
|
||||||
|
#define CLK_OTG1 (1 << 8)
|
||||||
|
#define CLK_HDMI (1 << 9)
|
||||||
|
#define CLK_UART4 (1 << 10)
|
||||||
|
#define CLK_AHB_MON (1 << 11)
|
||||||
|
#define CLK_SMB4 (1 << 12)
|
||||||
|
#define CLK_DES (1 << 13)
|
||||||
|
#define CLK_X2D (1 << 14)
|
||||||
|
#define CLK_P1 (1 << 15)
|
||||||
|
#define JZ_DDCDR 0x0000002c /* DDR clock divider register */
|
||||||
|
#define JZ_VPUCDR 0x00000030 /* VPU clock divider register */
|
||||||
|
#define JZ_I2SCDR 0x00000060 /* I2S device clock divider register */
|
||||||
|
#define JZ_I2S1CDR 0x000000a0 /* I2S device clock divider register */
|
||||||
|
#define JZ_USBCDR 0x00000050 /* OTG PHY clock divider register */
|
||||||
|
#define JZ_LP0CDR 0x00000054 /* LCD0 pix clock divider register */
|
||||||
|
#define JZ_LP1CDR 0x00000064 /* LCD1 pix clock divider register */
|
||||||
|
#define JZ_MSC0CDR 0x00000068 /* MSC0 clock divider register */
|
||||||
|
#define JZ_MSC1CDR 0x000000a4 /* MSC1 clock divider register */
|
||||||
|
#define JZ_MSC2CDR 0x000000a8 /* MSC2 clock divider register */
|
||||||
|
#define MSCCDR_SCLK_A 0x40000000
|
||||||
|
#define MSCCDR_MPLL 0x80000000
|
||||||
|
#define MSCCDR_CE 0x20000000
|
||||||
|
#define MSCCDR_BUSY 0x10000000
|
||||||
|
#define MSCCDR_STOP 0x08000000
|
||||||
|
#define MSCCDR_PHASE 0x00008000 /* 0 - 90deg phase, 1 - 180 */
|
||||||
|
#define MSCCDR_DIV_M 0x000000ff /* src / ((div + 1) * 2) */
|
||||||
|
#define UHCCDR_DIV_M 0x000000ff
|
||||||
|
#define JZ_UHCCDR 0x0000006c /* UHC 48M clock divider register */
|
||||||
|
#define UHCCDR_SCLK_A 0x00000000
|
||||||
|
#define UHCCDR_MPLL 0x40000000
|
||||||
|
#define UHCCDR_EPLL 0x80000000
|
||||||
|
#define UHCCDR_OTG_PHY 0xc0000000
|
||||||
|
#define UHCCDR_CLK_MASK 0xc0000000
|
||||||
|
#define UHCCDR_CE 0x20000000
|
||||||
|
#define UHCCDR_BUSY 0x10000000
|
||||||
|
#define UHCCDR_STOP 0x08000000
|
||||||
|
#define UHCCDR_DIV_M 0x000000ff
|
||||||
|
#define UHCCDR_DIV(d) (d)
|
||||||
|
#define JZ_SSICDR 0x00000074 /* SSI clock divider register */
|
||||||
|
#define JZ_CIMCDR 0x0000007c /* CIM MCLK clock divider register */
|
||||||
|
#define JZ_PCMCDR 0x00000084 /* PCM device clock divider register */
|
||||||
|
#define JZ_GPUCDR 0x00000088 /* GPU clock divider register */
|
||||||
|
#define JZ_HDMICDR 0x0000008c /* HDMI clock divider register */
|
||||||
|
#define JZ_BCHCDR 0x000000ac /* BCH clock divider register */
|
||||||
|
#define JZ_CPM_INTR 0x000000b0 /* CPM interrupt register */
|
||||||
|
#define JZ_CPM_INTRE 0x000000b4 /* CPM interrupt enable register */
|
||||||
|
#define JZ_CPSPR 0x00000034 /* CPM scratch register */
|
||||||
|
#define JZ_CPSRPR 0x00000038 /* CPM scratch protected register */
|
||||||
|
#define JZ_USBPCR 0x0000003c /* USB parameter control register */
|
||||||
|
#define PCR_USB_MODE 0x80000000 /* 1 - otg */
|
||||||
|
#define PCR_AVLD_REG 0x40000000
|
||||||
|
#define PCR_IDPULLUP_MASK 0x30000000
|
||||||
|
#define PCR_INCR_MASK 0x08000000
|
||||||
|
#define PCR_TCRISETUNE 0x04000000
|
||||||
|
#define PCR_COMMONONN 0x02000000
|
||||||
|
#define PCR_VBUSVLDEXT 0x01000000
|
||||||
|
#define PCR_VBUSVLDEXTSEL 0x00800000
|
||||||
|
#define PCR_POR 0x00400000
|
||||||
|
#define PCR_SIDDQ 0x00200000
|
||||||
|
#define PCR_OTG_DISABLE 0x00100000
|
||||||
|
#define PCR_COMPDISTN_M 0x000e0000
|
||||||
|
#define PCR_OTGTUNE 0x0001c000
|
||||||
|
#define PCR_SQRXTUNE 0x00003800
|
||||||
|
#define PCR_TXFSLSTUNE 0x00000780
|
||||||
|
#define PCR_TXPREEMPHTUNE 0x00000040
|
||||||
|
#define PCR_TXHSXVTUNE 0x00000030
|
||||||
|
#define PCR_TXVREFTUNE 0x0000000f
|
||||||
|
#define JZ_USBRDT 0x00000040 /* Reset detect timer register */
|
||||||
|
#define USBRDT_USBRDT_SHIFT 0
|
||||||
|
#define USBRDT_USBRDT_WIDTH 23
|
||||||
|
#define USBRDT_VBFIL_LD_EN 0x01000000
|
||||||
|
#define JZ_USBVBFIL 0x00000044 /* USB jitter filter register */
|
||||||
|
#define USBVBFIL_IDDIGFIL_SHIFT 16
|
||||||
|
#define USBVBFIL_IDDIGFIL_WIDTH 16
|
||||||
|
#define USBVBFIL_USBVBFIL_SHIFT 0
|
||||||
|
#define USBVBFIL_USBVBFIL_WIDTH 16
|
||||||
|
#define JZ_USBPCR1 0x00000048 /* USB parameter control register 1 */
|
||||||
|
#define PCR_SYNOPSYS 0x10000000 /* Mentor mode otherwise */
|
||||||
|
#define PCR_REFCLK_CORE 0x08000000
|
||||||
|
#define PCR_REFCLK_XO25 0x04000000
|
||||||
|
#define PCR_REFCLK_CO 0x00000000
|
||||||
|
#define PCR_REFCLK_M 0x0c000000
|
||||||
|
#define PCR_CLK_M 0x03000000 /* clock */
|
||||||
|
#define PCR_CLK_192 0x03000000 /* 19.2MHz */
|
||||||
|
#define PCR_CLK_48 0x02000000 /* 48MHz */
|
||||||
|
#define PCR_CLK_24 0x01000000 /* 24MHz */
|
||||||
|
#define PCR_CLK_12 0x00000000 /* 12MHz */
|
||||||
|
#define PCR_DMPD1 0x00800000 /* pull down D- on port 1 */
|
||||||
|
#define PCR_DPPD1 0x00400000 /* pull down D+ on port 1 */
|
||||||
|
#define PCR_PORT0_RST 0x00200000 /* port 0 reset */
|
||||||
|
#define PCR_PORT1_RST 0x00100000 /* port 1 reset */
|
||||||
|
#define PCR_WORD_I_F0 0x00080000 /* 1: 16bit/30M, 8/60 otherw. */
|
||||||
|
#define PCR_WORD_I_F1 0x00040000 /* same for port 1 */
|
||||||
|
#define PCR_COMPDISTUNE 0x00038000 /* disconnect threshold */
|
||||||
|
#define PCR_SQRXTUNE1 0x00007000 /* squelch threshold */
|
||||||
|
#define PCR_TXFSLSTUNE1 0x00000f00 /* FS/LS impedance adj. */
|
||||||
|
#define PCR_TXPREEMPH 0x00000080 /* HS transm. pre-emphasis */
|
||||||
|
#define PCR_TXHSXVTUNE1 0x00000060 /* dp/dm voltage adj. */
|
||||||
|
#define PCR_TXVREFTUNE1 0x00000017 /* HS DC voltage adj. */
|
||||||
|
#define PCR_TXRISETUNE1 0x00000001 /* rise/fall wave adj. */
|
||||||
|
|
||||||
|
/* power manager */
|
||||||
|
#define JZ_LPCR 0x00000004
|
||||||
|
#define LPCR_PD_SCPU (1u << 31) /* CPU1 power down */
|
||||||
|
#define LPCR_PD_VPU (1u << 30) /* VPU power down */
|
||||||
|
#define LPCR_PD_GPU (1u << 29) /* GPU power down */
|
||||||
|
#define LPCR_PD_GPS (1u << 28) /* GPS power down */
|
||||||
|
#define LPCR_SCPUS (1u << 27) /* CPU1 power down status */
|
||||||
|
#define LPCR_VPUS (1u << 26) /* VPU power down status */
|
||||||
|
#define LPCR_GPUS (1u << 25) /* GPU power down status */
|
||||||
|
#define LPCR_GPSS (1u << 24) /* GPS power down status */
|
||||||
|
#define LPCR_GPU_IDLE (1u << 20) /* GPU idle status */
|
||||||
|
#define LPCR_PST_SHIFT 8 /* Power stability time */
|
||||||
|
#define LPCR_PST_MASK (0xFFFu << 8)
|
||||||
|
#define LPCR_DUTY_SHIFT 3 /* CPU clock duty */
|
||||||
|
#define LPCR_DUTY_MASK (0x1Fu << 3)
|
||||||
|
#define LPCR_DOZE (1u << 2) /* Doze mode */
|
||||||
|
#define LPCR_LPM_SHIFT 0 /* Low power mode */
|
||||||
|
#define LPCR_LPM_MASK (0x03u << 0)
|
||||||
|
|
||||||
|
#define JZ_OPCR 0x00000024 /* Oscillator Power Control Reg. */
|
||||||
|
#define OPCR_IDLE_DIS 0x80000000 /* don't stop CPU clk on idle */
|
||||||
|
#define OPCR_GPU_CLK_ST 0x40000000 /* stop GPU clock */
|
||||||
|
#define OPCR_L2CM_M 0x0c000000
|
||||||
|
#define OPCR_L2CM_ON 0x00000000 /* L2 stays on in sleep */
|
||||||
|
#define OPCR_L2CM_RET 0x04000000 /* L2 retention mode in sleep */
|
||||||
|
#define OPCR_L2CM_OFF 0x08000000 /* L2 powers down in sleep */
|
||||||
|
#define OPCR_SPENDN0 0x00000080 /* 0 - OTG port forced down */
|
||||||
|
#define OPCR_SPENDN1 0x00000040 /* 0 - UHC port forced down */
|
||||||
|
#define OPCR_BUS_MODE 0x00000020 /* 1 - bursts */
|
||||||
|
#define OPCR_O1SE 0x00000010 /* EXTCLK on in sleep */
|
||||||
|
#define OPCR_PD 0x00000008 /* P0 down in sleep */
|
||||||
|
#define OPCR_ERCS 0x00000004 /* 1 RTCCLK, 0 EXTCLK/512 */
|
||||||
|
#define OPCR_CPU_MODE 0x00000002 /* 1 access 'accelerated' */
|
||||||
|
#define OPCR_OSE 0x00000001 /* disable EXTCLK */
|
||||||
|
|
||||||
|
#define JZ_SPCR0 0x000000b8 /* SRAM Power Control Registers */
|
||||||
|
#define JZ_SPCR1 0x000000bc
|
||||||
|
#define JZ_SRBC 0x000000c4 /* Soft Reset & Bus Control */
|
||||||
|
#define SRBC_UHC_SR 0x00004000 /* UHC soft reset*/
|
||||||
|
|
||||||
|
/*
|
||||||
|
* random number generator
|
||||||
|
*
|
||||||
|
* Its function currently isn't documented by Ingenic.
|
||||||
|
* However, testing suggests that it works as expected.
|
||||||
|
*/
|
||||||
|
#define JZ_ERNG 0x000000d8
|
||||||
|
#define JZ_RNG 0x000000dc
|
||||||
|
|
||||||
|
/* Interrupt controller */
|
||||||
|
#define JZ_ICBASE 0x10001000 /* IC base address */
|
||||||
|
#define JZ_ICSR0 0x00000000 /* raw IRQ line status */
|
||||||
|
#define JZ_ICMR0 0x00000004 /* IRQ mask, 1 masks IRQ */
|
||||||
|
#define JZ_ICMSR0 0x00000008 /* sets bits in mask register */
|
||||||
|
#define JZ_ICMCR0 0x0000000c /* clears bits in mask register */
|
||||||
|
#define JZ_ICPR0 0x00000010 /* line status after masking */
|
||||||
|
|
||||||
|
#define JZ_ICSR1 0x00000020 /* raw IRQ line status */
|
||||||
|
#define JZ_ICMR1 0x00000024 /* IRQ mask, 1 masks IRQ */
|
||||||
|
#define JZ_ICMSR1 0x00000028 /* sets bits in mask register */
|
||||||
|
#define JZ_ICMCR1 0x0000002c /* clears bits in maks register */
|
||||||
|
#define JZ_ICPR1 0x00000030 /* line status after masking */
|
||||||
|
|
||||||
|
#define JZ_DSR0 0x00000034 /* source for PDMA */
|
||||||
|
#define JZ_DMR0 0x00000038 /* mask for PDMA */
|
||||||
|
#define JZ_DPR0 0x0000003c /* pending for PDMA */
|
||||||
|
|
||||||
|
#define JZ_DSR1 0x00000040 /* source for PDMA */
|
||||||
|
#define JZ_DMR1 0x00000044 /* mask for PDMA */
|
||||||
|
#define JZ_DPR1 0x00000048 /* pending for PDMA */
|
||||||
|
|
||||||
|
/* memory controller */
|
||||||
|
#define JZ_DMMAP0 0x13010024
|
||||||
|
#define JZ_DMMAP1 0x13010028
|
||||||
|
#define DMMAP_BASE 0x0000ff00 /* base PADDR of memory chunk */
|
||||||
|
#define DMMAP_MASK 0x000000ff /* mask which bits of PADDR are
|
||||||
|
* constant */
|
||||||
|
/* USB controllers */
|
||||||
|
#define JZ_EHCI_BASE 0x13490000
|
||||||
|
#define JZ_EHCI_REG_UTMI_BUS 0x000000b0
|
||||||
|
#define UTMI_BUS_WIDTH 0x00000040
|
||||||
|
#define JZ_OHCI_BASE 0x134a0000
|
||||||
|
|
||||||
|
#define JZ_DWC2_BASE 0x13500000
|
||||||
|
#define JZ_DWC2_GUSBCFG 0
|
||||||
|
|
||||||
|
/* Ethernet */
|
||||||
|
#define JZ_DME_BASE 0x16000000
|
||||||
|
#define JZ_DME_IO 0
|
||||||
|
#define JZ_DME_DATA 2
|
||||||
|
|
||||||
|
/* GPIO */
|
||||||
|
#define JZ_GPIO_A_BASE 0x10010000
|
||||||
|
#define JZ_GPIO_B_BASE 0x10010100
|
||||||
|
#define JZ_GPIO_C_BASE 0x10010200
|
||||||
|
#define JZ_GPIO_D_BASE 0x10010300
|
||||||
|
#define JZ_GPIO_E_BASE 0x10010400
|
||||||
|
#define JZ_GPIO_F_BASE 0x10010500
|
||||||
|
|
||||||
|
/* GPIO registers per port */
|
||||||
|
#define JZ_GPIO_PIN 0x00000000 /* pin level register */
|
||||||
|
/* 0 - normal gpio, 1 - interrupt */
|
||||||
|
#define JZ_GPIO_INT 0x00000010 /* interrupt register */
|
||||||
|
#define JZ_GPIO_INTS 0x00000014 /* interrupt set register */
|
||||||
|
#define JZ_GPIO_INTC 0x00000018 /* interrupt clear register */
|
||||||
|
/*
|
||||||
|
* INT == 1: 1 disables interrupt
|
||||||
|
* INT == 0: device select, see below
|
||||||
|
*/
|
||||||
|
#define JZ_GPIO_MASK 0x00000020 /* port mask register */
|
||||||
|
#define JZ_GPIO_MASKS 0x00000024 /* port mask set register */
|
||||||
|
#define JZ_GPIO_MASKC 0x00000028 /* port mask clear register */
|
||||||
|
/*
|
||||||
|
* INT == 1: 0 - level triggered, 1 - edge triggered
|
||||||
|
* INT == 0: 0 - device select, see below
|
||||||
|
*/
|
||||||
|
#define JZ_GPIO_PAT1 0x00000030 /* pattern 1 register */
|
||||||
|
#define JZ_GPIO_PAT1S 0x00000034 /* pattern 1 set register */
|
||||||
|
#define JZ_GPIO_PAT1C 0x00000038 /* pattern 1 clear register */
|
||||||
|
/*
|
||||||
|
* INT == 1:
|
||||||
|
* PAT1 == 0: 0 - trigger on low, 1 - trigger on high
|
||||||
|
* PAT0 == 1: 0 - trigger on falling edge, 1 - trigger on rising edge
|
||||||
|
* INT == 0:
|
||||||
|
* MASK == 0:
|
||||||
|
* PAT1 == 0: 0 - device 0, 1 - device 1
|
||||||
|
* PAT0 == 1: 0 - device 2, 1 - device 3
|
||||||
|
* MASK == 1:
|
||||||
|
* PAT1 == 0: set gpio output
|
||||||
|
* PAT1 == 1: pin is input
|
||||||
|
*/
|
||||||
|
#define JZ_GPIO_PAT0 0x00000040 /* pattern 0 register */
|
||||||
|
#define JZ_GPIO_PAT0S 0x00000044 /* pattern 0 set register */
|
||||||
|
#define JZ_GPIO_PAT0C 0x00000048 /* pattern 0 clear register */
|
||||||
|
/* 1 - interrupt happened */
|
||||||
|
#define JZ_GPIO_FLAG 0x00000050 /* flag register */
|
||||||
|
#define JZ_GPIO_FLAGC 0x00000058 /* flag clear register */
|
||||||
|
/* 1 - disable pull up/down resistors */
|
||||||
|
#define JZ_GPIO_DPULL 0x00000070 /* pull disable register */
|
||||||
|
#define JZ_GPIO_DPULLS 0x00000074 /* pull disable set register */
|
||||||
|
#define JZ_GPIO_DPULLC 0x00000078 /* pull disable clear register */
|
||||||
|
/* the following are uncommented in the manual */
|
||||||
|
#define JZ_GPIO_DRVL 0x00000080 /* drive low register */
|
||||||
|
#define JZ_GPIO_DRVLS 0x00000084 /* drive low set register */
|
||||||
|
#define JZ_GPIO_DRVLC 0x00000088 /* drive low clear register */
|
||||||
|
#define JZ_GPIO_DIR 0x00000090 /* direction register */
|
||||||
|
#define JZ_GPIO_DIRS 0x00000094 /* direction register */
|
||||||
|
#define JZ_GPIO_DIRC 0x00000098 /* direction register */
|
||||||
|
#define JZ_GPIO_DRVH 0x000000a0 /* drive high register */
|
||||||
|
#define JZ_GPIO_DRVHS 0x000000a4 /* drive high set register */
|
||||||
|
#define JZ_GPIO_DRVHC 0x000000a8 /* drive high clear register */
|
||||||
|
|
||||||
|
/* I2C / SMBus */
|
||||||
|
#define JZ_SMB0_BASE 0x10050000
|
||||||
|
#define JZ_SMB1_BASE 0x10051000
|
||||||
|
#define JZ_SMB2_BASE 0x10052000
|
||||||
|
#define JZ_SMB3_BASE 0x10053000
|
||||||
|
#define JZ_SMB4_BASE 0x10054000
|
||||||
|
|
||||||
|
/* SMBus register offsets, per port */
|
||||||
|
#define JZ_SMBCON 0x00 /* SMB control */
|
||||||
|
#define JZ_STPHLD 0x80 /* Stop Hold Enable bit */
|
||||||
|
#define JZ_SLVDIS 0x40 /* 1 - slave disabled */
|
||||||
|
#define JZ_REST 0x20 /* 1 - allow RESTART */
|
||||||
|
#define JZ_MATP 0x10 /* 1 - enable 10bit addr. for master */
|
||||||
|
#define JZ_SATP 0x08 /* 1 - enable 10bit addr. for slave */
|
||||||
|
#define JZ_SPD_M 0x06 /* bus speed control */
|
||||||
|
#define JZ_SPD_100KB 0x02 /* 100kBit/s mode */
|
||||||
|
#define JZ_SPD_400KB 0x04 /* 400kBit/s mode */
|
||||||
|
#define JZ_MD 0x01 /* enable master */
|
||||||
|
#define JZ_SMBTAR 0x04 /* SMB target address */
|
||||||
|
#define JZ_SMATP 0x1000 /* enable 10bit master addr */
|
||||||
|
#define JZ_SPECIAL 0x0800 /* 1 - special command */
|
||||||
|
#define JZ_START 0x0400 /* 1 - send START */
|
||||||
|
#define JZ_SMBTAR_M 0x03ff /* target address */
|
||||||
|
#define JZ_SMBSAR 0x08 /* SMB slave address */
|
||||||
|
#define JZ_SMBDC 0x10 /* SMB data buffer and command */
|
||||||
|
#define JZ_CMD 0x100 /* 1 - read, 0 - write */
|
||||||
|
#define JZ_DATA 0x0ff
|
||||||
|
#define JZ_SMBSHCNT 0x14 /* Standard speed SMB SCL high count */
|
||||||
|
#define JZ_SMBSLCNT 0x18 /* Standard speed SMB SCL low count */
|
||||||
|
#define JZ_SMBFHCNT 0x1C /* Fast speed SMB SCL high count */
|
||||||
|
#define JZ_SMBFLCNT 0x20 /* Fast speed SMB SCL low count */
|
||||||
|
#define JZ_SMBINTST 0x2C /* SMB Interrupt Status */
|
||||||
|
#define JZ_ISTT 0x400 /* START or RESTART occured */
|
||||||
|
#define JZ_ISTP 0x200 /* STOP occured */
|
||||||
|
#define JZ_TXABT 0x40 /* ABORT occured */
|
||||||
|
#define JZ_TXEMP 0x10 /* TX FIFO is low */
|
||||||
|
#define JZ_TXOF 0x08 /* TX FIFO is high */
|
||||||
|
#define JZ_RXFL 0x04 /* RX FIFO is at JZ_SMBRXTL*/
|
||||||
|
#define JZ_RXOF 0x02 /* RX FIFO is high */
|
||||||
|
#define JZ_RXUF 0x01 /* RX FIFO underflow */
|
||||||
|
#define JZ_SMBINTM 0x30 /* SMB Interrupt Mask */
|
||||||
|
#define JZ_SMBRXTL 0x38 /* SMB RxFIFO Threshold */
|
||||||
|
#define JZ_SMBTXTL 0x3C /* SMB TxFIFO Threshold */
|
||||||
|
#define JZ_SMBCINT 0x40 /* Clear Interrupts */
|
||||||
|
#define JZ_CLEARALL 0x01
|
||||||
|
#define JZ_SMBCRXUF 0x44 /* Clear RXUF Interrupt */
|
||||||
|
#define JZ_SMBCRXOF 0x48 /* Clear RX_OVER Interrupt */
|
||||||
|
#define JZ_SMBCTXOF 0x4C /* Clear TX_OVER Interrupt */
|
||||||
|
#define JZ_SMBCRXREQ 0x50 /* Clear RDREQ Interrupt */
|
||||||
|
#define JZ_SMBCTXABT 0x54 /* Clear TX_ABRT Interrupt */
|
||||||
|
#define JZ_SMBCRXDN 0x58 /* Clear RX_DONE Interrupt */
|
||||||
|
#define JZ_SMBCACT 0x5c /* Clear ACTIVITY Interrupt */
|
||||||
|
#define JZ_SMBCSTP 0x60 /* Clear STOP Interrupt */
|
||||||
|
#define JZ_SMBCSTT 0x64 /* Clear START Interrupt */
|
||||||
|
#define JZ_SMBCGC 0x68 /* Clear GEN_CALL Interrupt */
|
||||||
|
#define JZ_SMBENB 0x6C /* SMB Enable */
|
||||||
|
#define JZ_ENABLE 0x01
|
||||||
|
#define JZ_SMBST 0x70 /* SMB Status register */
|
||||||
|
#define JZ_SLVACT 0x40 /* slave is active */
|
||||||
|
#define JZ_MSTACT 0x20 /* master is active */
|
||||||
|
#define JZ_RFF 0x10 /* RX FIFO is full */
|
||||||
|
#define JZ_RFNE 0x08 /* RX FIFO not empty */
|
||||||
|
#define JZ_TFE 0x04 /* TX FIFO is empty */
|
||||||
|
#define JZ_TFNF 0x02 /* TX FIFO is not full */
|
||||||
|
#define JZ_ACT 0x01 /* JZ_SLVACT | JZ_MSTACT */
|
||||||
|
#define JZ_SMBABTSRC 0x80 /* SMB Transmit Abort Status Register */
|
||||||
|
#define JZ_SMBDMACR 0x88 /* DMA Control Register */
|
||||||
|
#define JZ_SMBDMATDL 0x8c /* DMA Transmit Data Level */
|
||||||
|
#define JZ_SMBDMARDL 0x90 /* DMA Receive Data Level */
|
||||||
|
#define JZ_SMBSDASU 0x94 /* SMB SDA Setup Register */
|
||||||
|
#define JZ_SMBACKGC 0x98 /* SMB ACK General Call Register */
|
||||||
|
#define JZ_SMBENBST 0x9C /* SMB Enable Status Register */
|
||||||
|
#define JZ_SMBSDAHD 0xD0 /* SMB SDA HolD time Register */
|
||||||
|
#define JZ_HDENB 0x100 /* enable hold time */
|
||||||
|
|
||||||
|
/* SD/MMC hosts */
|
||||||
|
#define JZ_MSC0_BASE 0x13450000
|
||||||
|
#define JZ_MSC1_BASE 0x13460000
|
||||||
|
#define JZ_MSC2_BASE 0x13470000
|
||||||
|
|
||||||
|
#define JZ_MSC_CTRL 0x00
|
||||||
|
#define JZ_SEND_CCSD 0x8000
|
||||||
|
#define JZ_SEND_AS_CCSD 0x4000
|
||||||
|
#define JZ_EXIT_MULTIPLE 0x0080
|
||||||
|
#define JZ_EXIT_TRANSFER 0x0040
|
||||||
|
#define JZ_START_READWAIT 0x0020
|
||||||
|
#define JZ_STOP_READWAIT 0x0010
|
||||||
|
#define JZ_RESET 0x0008
|
||||||
|
#define JZ_START_OP 0x0004
|
||||||
|
#define JZ_CLOCK_CTRL_M 0x0003
|
||||||
|
#define JZ_CLOCK_START 0x0002
|
||||||
|
#define JZ_CLOCK_STOP 0x0001
|
||||||
|
#define JZ_MSC_STAT 0x04
|
||||||
|
#define JZ_AUTO_CMD12_DONE 0x80000000
|
||||||
|
#define JZ_AUTO_CMD23_DONE 0x40000000
|
||||||
|
#define JZ_SVS 0x20000000
|
||||||
|
#define JZ_PIN_LEVEL_M 0x1f000000
|
||||||
|
#define JZ_BCE 0x00100000 /* boot CRC error */
|
||||||
|
#define JZ_BDE 0x00080000 /* boot data end */
|
||||||
|
#define JZ_BAE 0x00040000 /* boot acknowledge error */
|
||||||
|
#define JZ_BAR 0x00020000 /* boot ack. received */
|
||||||
|
#define JZ_DMAEND 0x00010000
|
||||||
|
#define JZ_IS_RESETTING 0x00008000
|
||||||
|
#define JZ_SDIO_INT_ACTIVE 0x00004000
|
||||||
|
#define JZ_PRG_DONE 0x00002000
|
||||||
|
#define JZ_DATA_TRAN_DONE 0x00001000
|
||||||
|
#define JZ_END_CMD_RES 0x00000800
|
||||||
|
#define JZ_DATA_FIFO_AFULL 0x00000400
|
||||||
|
#define JZ_IS_READWAIT 0x00000200
|
||||||
|
#define JZ_CLK_EN 0x00000100
|
||||||
|
#define JZ_DATA_FIFO_FULL 0x00000080
|
||||||
|
#define JZ_DATA_FIFO_EMPTY 0x00000040
|
||||||
|
#define JZ_CRC_RES_ERR 0x00000020
|
||||||
|
#define JZ_CRC_READ_ERR 0x00000010
|
||||||
|
#define JZ_CRC_WRITE_ERR_M 0x0000000c
|
||||||
|
#define JZ_CRC_WRITE_OK 0x00000000
|
||||||
|
#define JZ_CRC_CARD_ERR 0x00000004
|
||||||
|
#define JZ_CRC_NO_STATUS 0x00000008
|
||||||
|
#define JZ_TIME_OUT_RES 0x00000002
|
||||||
|
#define JZ_TIME_OUT_READ 0x00000001
|
||||||
|
#define JZ_MSC_CLKRT 0x08
|
||||||
|
#define JZ_DEV_CLK 0x0
|
||||||
|
#define JZ_DEV_CLK_2 0x1 /* DEV_CLK / 2 */
|
||||||
|
#define JZ_DEV_CLK_4 0x2 /* DEV_CLK / 4 */
|
||||||
|
#define JZ_DEV_CLK_8 0x3 /* DEV_CLK / 8 */
|
||||||
|
#define JZ_DEV_CLK_16 0x4 /* DEV_CLK / 16 */
|
||||||
|
#define JZ_DEV_CLK_32 0x5 /* DEV_CLK / 32 */
|
||||||
|
#define JZ_DEV_CLK_64 0x6 /* DEV_CLK / 64 */
|
||||||
|
#define JZ_DEV_CLK_128 0x7 /* DEV_CLK / 128 */
|
||||||
|
#define JZ_MSC_CMDAT 0x0c
|
||||||
|
#define JZ_CCS_EXPECTED 0x80000000
|
||||||
|
#define JZ_READ_CEATA 0x40000000
|
||||||
|
#define JZ_DIS_BOOT 0x08000000
|
||||||
|
#define JZ_ENA_BOOT 0x04000000
|
||||||
|
#define JZ_EXP_BOOT_ACK 0x02000000
|
||||||
|
#define JZ_BOOT_MODE 0x01000000
|
||||||
|
#define JZ_AUTO_CMD23 0x00040000
|
||||||
|
#define JZ_SDIO_PRDT 0x00020000
|
||||||
|
#define JZ_AUTO_CMD12 0x00010000
|
||||||
|
#define JZ_RTRG_M 0x0000c000 /* receive FIFO trigger */
|
||||||
|
#define JZ_RTRG_16 0x00000000 /* >= 16 */
|
||||||
|
#define JZ_RTRG_32 0x00004000 /* >= 32 */
|
||||||
|
#define JZ_RTRG_64 0x00008000 /* >= 64 */
|
||||||
|
#define JZ_RTRG_96 0x0000c000 /* >= 96 */
|
||||||
|
#define JZ_TTRG_M 0x00003000 /* transmit FIFO trigger */
|
||||||
|
#define JZ_TTRG_16 0x00000000 /* >= 16 */
|
||||||
|
#define JZ_TTRG_32 0x00001000 /* >= 32 */
|
||||||
|
#define JZ_TTRG_64 0x00002000 /* >= 64 */
|
||||||
|
#define JZ_TTRG_96 0x00003000 /* >= 96 */
|
||||||
|
#define JZ_IO_ABORT 0x00000800
|
||||||
|
#define JZ_BUS_WIDTH_M 0x00000600
|
||||||
|
#define JZ_BUS_1BIT 0x00000000
|
||||||
|
#define JZ_BUS_4BIT 0x00000400
|
||||||
|
#define JZ_BUS_8BIT 0x00000600
|
||||||
|
#define JZ_INIT 0x00000080 /* send 80 clk init before cmd */
|
||||||
|
#define JZ_BUSY 0x00000040
|
||||||
|
#define JZ_STREAM 0x00000020
|
||||||
|
#define JZ_WRITE 0x00000010 /* read otherwise */
|
||||||
|
#define JZ_DATA_EN 0x00000008
|
||||||
|
#define JZ_RESPONSE_M 0x00000007 /* response format */
|
||||||
|
#define JZ_RES_NONE 0x00000000
|
||||||
|
#define JZ_RES_R1 0x00000001 /* R1 and R1b */
|
||||||
|
#define JZ_RES_R2 0x00000002
|
||||||
|
#define JZ_RES_R3 0x00000003
|
||||||
|
#define JZ_RES_R4 0x00000004
|
||||||
|
#define JZ_RES_R5 0x00000005
|
||||||
|
#define JZ_RES_R6 0x00000006
|
||||||
|
#define JZ_RES_R7 0x00000007
|
||||||
|
#define JZ_MSC_RESTO 0x10 /* 16bit response timeout in MSC_CLK */
|
||||||
|
#define JZ_MSC_RDTO 0x14 /* 32bit read timeout in MSC_CLK */
|
||||||
|
#define JZ_MSC_BLKLEN 0x18 /* 16bit block length */
|
||||||
|
#define JZ_MSC_NOB 0x1c /* 16bit block counter */
|
||||||
|
#define JZ_MSC_SNOB 0x20 /* 16bit successful block counter */
|
||||||
|
#define JZ_MSC_IMASK 0x24 /* interrupt mask */
|
||||||
|
#define JZ_INT_AUTO_CMD23_DONE 0x40000000
|
||||||
|
#define JZ_INT_SVS 0x20000000
|
||||||
|
#define JZ_INT_PIN_LEVEL_M 0x1f000000
|
||||||
|
#define JZ_INT_BCE 0x00100000
|
||||||
|
#define JZ_INT_BDE 0x00080000
|
||||||
|
#define JZ_INT_BAE 0x00040000
|
||||||
|
#define JZ_INT_BAR 0x00020000
|
||||||
|
#define JZ_INT_DMAEND 0x00010000
|
||||||
|
#define JZ_INT_AUTO_CMD12_DONE 0x00008000
|
||||||
|
#define JZ_INT_DATA_FIFO_FULL 0x00004000
|
||||||
|
#define JZ_INT_DATA_FIFO_EMPTY 0x00002000
|
||||||
|
#define JZ_INT_CRC_RES_ERR 0x00001000
|
||||||
|
#define JZ_INT_CRC_READ_ERR 0x00000800
|
||||||
|
#define JZ_INT_CRC_WRITE_ERR 0x00000400
|
||||||
|
#define JZ_INT_TIMEOUT_RES 0x00000200
|
||||||
|
#define JZ_INT_TIMEOUT_READ 0x00000100
|
||||||
|
#define JZ_INT_SDIO 0x00000080
|
||||||
|
#define JZ_INT_TXFIFO_WR_REQ 0x00000040
|
||||||
|
#define JZ_INT_RXFIFO_RD_REQ 0x00000020
|
||||||
|
#define JZ_INT_END_CMD_RES 0x00000004
|
||||||
|
#define JZ_INT_PRG_DONE 0x00000002
|
||||||
|
#define JZ_INT_DATA_TRAN_DONE 0x00000001
|
||||||
|
#define JZ_MSC_IFLG 0x28 /* interrupt flags */
|
||||||
|
#define JZ_MSC_CMD 0x2c /* 6bit CMD index */
|
||||||
|
#define JZ_MSC_ARG 0x30 /* 32bit argument */
|
||||||
|
#define JZ_MSC_RES 0x34 /* 8x16bit response data FIFO */
|
||||||
|
#define JZ_MSC_RXFIFO 0x38
|
||||||
|
#define JZ_MSC_TXFIFO 0x3c
|
||||||
|
#define JZ_MSC_LPM 0x40
|
||||||
|
#define JZ_DRV_SEL_M 0xc0000000
|
||||||
|
#define JZ_FALLING_EDGE 0x00000000
|
||||||
|
#define JZ_RISING_1NS 0x40000000 /* 1ns delay */
|
||||||
|
#define JZ_RISING_4 0x80000000 /* 1/4 MSC_CLK delay */
|
||||||
|
#define JZ_SMP_SEL 0x20000000 /* 1 - rising edge */
|
||||||
|
#define JZ_LPM 0x00000001 /* low power mode */
|
||||||
|
#define JZ_MSC_DMAC 0x44
|
||||||
|
#define JZ_MODE_SEL 0x80 /* 1 - specify transfer length */
|
||||||
|
#define JZ_AOFST_M 0x60 /* address offset in bytes */
|
||||||
|
#define JZ_AOFST_S 6 /* addrress offset shift */
|
||||||
|
#define JZ_ALIGNEN 0x10 /* allow non-32bit-aligned transfers */
|
||||||
|
#define JZ_INCR_M 0x0c /* burst type */
|
||||||
|
#define JZ_INCR_16 0x00
|
||||||
|
#define JZ_INCR_32 0x04
|
||||||
|
#define JZ_INCR_64 0x08
|
||||||
|
#define JZ_DMASEL 0x02 /* 1 - SoC DMAC, 0 - MSC built-in */
|
||||||
|
#define JZ_DMAEN 0x01 /* enable DMA */
|
||||||
|
#define JZ_MSC_DMANDA 0x48 /* next descriptor paddr */
|
||||||
|
#define JZ_MSC_DMADA 0x4c /* current descriptor */
|
||||||
|
#define JZ_MSC_DMALEN 0x50 /* transfer tength */
|
||||||
|
#define JZ_MSC_DMACMD 0x54
|
||||||
|
#define JZ_DMA_IDI_M 0xff000000
|
||||||
|
#define JZ_DMA_ID_M 0x00ff0000
|
||||||
|
#define JZ_DMA_AOFST_M 0x00000600
|
||||||
|
#define JZ_DMA_ALIGN 0x00000100
|
||||||
|
#define JZ_DMA_ENDI 0x00000002
|
||||||
|
#define JZ_DMA_LINK 0x00000001
|
||||||
|
#define JZ_MSC_CTRL2 0x58
|
||||||
|
#define JZ_PIP 0x1f000000 /* 1 - intr trigger on high */
|
||||||
|
#define JZ_RST_EN 0x00800000
|
||||||
|
#define JZ_STPRM 0x00000010
|
||||||
|
#define JZ_SVC 0x00000008
|
||||||
|
#define JZ_SMS_M 0x00000007
|
||||||
|
#define JZ_SMS_DEF 0x00000000 /* default speed */
|
||||||
|
#define JZ_SMS_HIGH 0x00000001 /* high speed */
|
||||||
|
#define JZ_SMS_SDR12 0x00000002
|
||||||
|
#define JZ_SMS_SDR25 0x00000003
|
||||||
|
#define JZ_SMS_SDR50 0x00000004
|
||||||
|
#define JZ_MSC_RTCNT 0x5c /* RT FIFO count */
|
||||||
|
|
||||||
|
/* EFUSE Slave Interface */
|
||||||
|
#define JZ_EFUSE 0x134100D0
|
||||||
|
#define JZ_EFUCTRL 0x00
|
||||||
|
#define JZ_EFUSE_BANK 0x40000000 /* select upper 4KBit */
|
||||||
|
#define JZ_EFUSE_ADDR_M 0x3fe00000 /* in bytes */
|
||||||
|
#define JZ_EFUSE_ADDR_SHIFT 21
|
||||||
|
#define JZ_EFUSE_SIZE_M 0x001f0000 /* in bytes */
|
||||||
|
#define JZ_EFUSE_SIZE_SHIFT 16
|
||||||
|
#define JZ_EFUSE_PROG 0x00008000 /* enable programming */
|
||||||
|
#define JZ_EFUSE_WRITE 0x00000002 /* write enable */
|
||||||
|
#define JZ_EFUSE_READ 0x00000001 /* read enable */
|
||||||
|
#define JZ_EFUCFG 0x04
|
||||||
|
#define JZ_EFUSE_INT_E 0x80000000 /* which IRQ? */
|
||||||
|
#define JZ_EFUSE_RD_ADJ_M 0x00f00000
|
||||||
|
#define JZ_EFUSE_RD_STROBE 0x000f0000
|
||||||
|
#define JZ_EFUSE_WR_ADJUST 0x0000f000
|
||||||
|
#define JZ_EFUSE_WR_STROBE 0x00000fff
|
||||||
|
#define JZ_EFUSTATE 0x08
|
||||||
|
#define JZ_EFUSE_GLOBAL_P 0x00008000 /* wr protect bits */
|
||||||
|
#define JZ_EFUSE_CHIPID_P 0x00004000
|
||||||
|
#define JZ_EFUSE_CUSTID_P 0x00002000
|
||||||
|
#define JZ_EFUSE_SECWR_EN 0x00001000
|
||||||
|
#define JZ_EFUSE_PC_P 0x00000800
|
||||||
|
#define JZ_EFUSE_HDMIKEY_P 0x00000400
|
||||||
|
#define JZ_EFUSE_SECKEY_P 0x00000200
|
||||||
|
#define JZ_EFUSE_SECBOOT_EN 0x00000100
|
||||||
|
#define JZ_EFUSE_HDMI_BUSY 0x00000004
|
||||||
|
#define JZ_EFUSE_WR_DONE 0x00000002
|
||||||
|
#define JZ_EFUSE_RD_DONE 0x00000001
|
||||||
|
#define JZ_EFUDATA0 0x0C
|
||||||
|
#define JZ_EFUDATA1 0x10
|
||||||
|
#define JZ_EFUDATA2 0x14
|
||||||
|
#define JZ_EFUDATA3 0x18
|
||||||
|
#define JZ_EFUDATA4 0x1C
|
||||||
|
#define JZ_EFUDATA5 0x20
|
||||||
|
#define JZ_EFUDATA6 0x24
|
||||||
|
#define JZ_EFUDATA7 0x28
|
||||||
|
|
||||||
|
/* NEMC */
|
||||||
|
#define JZ_NEMC_BASE 0x13410000
|
||||||
|
#define JZ_NEMC_SMCR(n) (0x10 + (n) * 4)
|
||||||
|
|
||||||
|
# define JZ_NEMC_SMCR_SMT_SHIFT 0
|
||||||
|
# define JZ_NEMC_SMCR_SMT_WIDTH 1
|
||||||
|
# define JZ_NEMC_SMCR_SMT_MASK (((1 << JZ_NEMC_SMCR_SMT_WIDTH) - 1) << JZ_NEMC_SMCR_SMT_SHIFT)
|
||||||
|
# define JZ_NEMC_SMCR_SMT_NORMAL (0 << JZ_NEMC_SMCR_SMT_SHIFT)
|
||||||
|
# define JZ_NEMC_SMCR_SMT_BROM (1 << JZ_NEMC_SMCR_SMT_SHIFT)
|
||||||
|
|
||||||
|
# define JZ_NEMC_SMCR_BL_SHIFT 1
|
||||||
|
# define JZ_NEMC_SMCR_BL_WIDTH 2
|
||||||
|
# define JZ_NEMC_SMCR_BL_MASK (((1 << JZ_NEMC_SMCR_BL_WIDTH) - 1) << JZ_NEMC_SMCR_BL_SHIFT)
|
||||||
|
# define JZ_NEMC_SMCR_BL(n) (((n) << JZ_NEMC_SMCR_BL_SHIFT)
|
||||||
|
|
||||||
|
# define JZ_NEMC_SMCR_BW_SHIFT 6
|
||||||
|
# define JZ_NEMC_SMCR_BW_WIDTH 2
|
||||||
|
# define JZ_NEMC_SMCR_BW_MASK (((1 << JZ_NEMC_SMCR_BW_WIDTH) - 1) << JZ_NEMC_SMCR_BW_SHIFT)
|
||||||
|
# define JZ_NEMC_SMCR_BW_8 (0 << JZ_NEMC_SMCR_BW_SHIFT)
|
||||||
|
|
||||||
|
# define JZ_NEMC_SMCR_TAS_SHIFT 8
|
||||||
|
# define JZ_NEMC_SMCR_TAS_WIDTH 4
|
||||||
|
# define JZ_NEMC_SMCR_TAS_MASK (((1 << JZ_NEMC_SMCR_TAS_WIDTH) - 1) << JZ_NEMC_SMCR_TAS_SHIFT)
|
||||||
|
|
||||||
|
# define JZ_NEMC_SMCR_TAH_SHIFT 12
|
||||||
|
# define JZ_NEMC_SMCR_TAH_WIDTH 4
|
||||||
|
# define JZ_NEMC_SMCR_TAH_MASK (((1 << JZ_NEMC_SMCR_TAH_WIDTH) - 1) << JZ_NEMC_SMCR_TAH_SHIFT)
|
||||||
|
|
||||||
|
# define JZ_NEMC_SMCR_TBP_SHIFT 16
|
||||||
|
# define JZ_NEMC_SMCR_TBP_WIDTH 4
|
||||||
|
# define JZ_NEMC_SMCR_TBP_MASK (((1 << JZ_NEMC_SMCR_TBP_WIDTH) - 1) << JZ_NEMC_SMCR_TBP_SHIFT)
|
||||||
|
|
||||||
|
# define JZ_NEMC_SMCR_TAW_SHIFT 20
|
||||||
|
# define JZ_NEMC_SMCR_TAW_WIDTH 4
|
||||||
|
# define JZ_NEMC_SMCR_TAW_MASK (((1 << JZ_NEMC_SMCR_TAW_WIDTH) - 1) << JZ_NEMC_SMCR_TAW_SHIFT)
|
||||||
|
|
||||||
|
# define JZ_NEMC_SMCR_STRV_SHIFT 24
|
||||||
|
# define JZ_NEMC_SMCR_STRV_WIDTH 4
|
||||||
|
# define JZ_NEMC_SMCR_STRV_MASK (((1 << JZ_NEMC_SMCR_STRV_WIDTH) - 1) << JZ_NEMC_SMCR_STRV_SHIFT)
|
||||||
|
|
||||||
|
#define JZ_NEMC_SACR(n) (0x30 + (n) * 4)
|
||||||
|
|
||||||
|
# define JZ_NEMC_SACR_MASK_SHIFT 0
|
||||||
|
# define JZ_NEMC_SACR_MASK_WIDTH 8
|
||||||
|
# define JZ_NEMC_SACR_MASK_MASK (((1 << JZ_NEMC_SACR_MASK_WIDTH) - 1) << JZ_NEMC_SACR_MASK_SHIFT)
|
||||||
|
|
||||||
|
# define JZ_NEMC_SACR_ADDR_SHIFT 0
|
||||||
|
# define JZ_NEMC_SACR_ADDR_WIDTH 8
|
||||||
|
# define JZ_NEMC_SACR_ADDR_MASK (((1 << JZ_NEMC_SACR_ADDR_WIDTH) - 1) << JZ_NEMC_SACR_ADDR_SHIFT)
|
||||||
|
|
||||||
|
#define JC_NEMC_NFSCR 0x50
|
||||||
|
|
||||||
|
#endif /* JZ4780_REGS_H */
|
337
sys/mips/ingenic/jz4780_timer.c
Normal file
337
sys/mips/ingenic/jz4780_timer.c
Normal file
@ -0,0 +1,337 @@
|
|||||||
|
/*-
|
||||||
|
* Copyright 2013-2015 Alexander Kabaev <kan@FreeBSD.org>
|
||||||
|
* Copyright 2013-2015 John Wehle <john@feith.com>
|
||||||
|
* All rights reserved.
|
||||||
|
*
|
||||||
|
* Redistribution and use in source and binary forms, with or without
|
||||||
|
* modification, are permitted provided that the following conditions
|
||||||
|
* are met:
|
||||||
|
* 1. Redistributions of source code must retain the above copyright
|
||||||
|
* notice, this list of conditions and the following disclaimer.
|
||||||
|
* 2. Redistributions in binary form must reproduce the above copyright
|
||||||
|
* notice, this list of conditions and the following disclaimer in the
|
||||||
|
* documentation and/or other materials provided with the distribution.
|
||||||
|
*
|
||||||
|
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
|
||||||
|
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||||
|
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
||||||
|
* ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
|
||||||
|
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
|
||||||
|
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
|
||||||
|
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
|
||||||
|
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
|
||||||
|
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
|
||||||
|
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
|
||||||
|
* SUCH DAMAGE.
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include <sys/cdefs.h>
|
||||||
|
__FBSDID("$FreeBSD$");
|
||||||
|
|
||||||
|
#include <sys/param.h>
|
||||||
|
#include <sys/systm.h>
|
||||||
|
#include <sys/bus.h>
|
||||||
|
#include <sys/kernel.h>
|
||||||
|
#include <sys/module.h>
|
||||||
|
#include <sys/malloc.h>
|
||||||
|
#include <sys/rman.h>
|
||||||
|
#include <sys/timetc.h>
|
||||||
|
#include <sys/timeet.h>
|
||||||
|
|
||||||
|
#include <machine/bus.h>
|
||||||
|
#include <machine/cpu.h>
|
||||||
|
#include <machine/hwfunc.h>
|
||||||
|
|
||||||
|
#include <dev/extres/clk/clk.h>
|
||||||
|
|
||||||
|
#include <dev/fdt/fdt_common.h>
|
||||||
|
#include <dev/ofw/ofw_bus.h>
|
||||||
|
#include <dev/ofw/ofw_bus_subr.h>
|
||||||
|
|
||||||
|
#include <mips/ingenic/jz4780_regs.h>
|
||||||
|
|
||||||
|
struct jz4780_timer_softc {
|
||||||
|
device_t dev;
|
||||||
|
struct resource * res[4];
|
||||||
|
void * ih_cookie;
|
||||||
|
struct eventtimer et;
|
||||||
|
struct timecounter tc;
|
||||||
|
};
|
||||||
|
|
||||||
|
static struct resource_spec jz4780_timer_spec[] = {
|
||||||
|
{ SYS_RES_MEMORY, 0, RF_ACTIVE },
|
||||||
|
{ SYS_RES_IRQ, 0, RF_ACTIVE }, /* OST */
|
||||||
|
{ SYS_RES_IRQ, 1, RF_ACTIVE }, /* TC5 */
|
||||||
|
{ SYS_RES_IRQ, 2, RF_ACTIVE }, /* TC0-4,6 */
|
||||||
|
{ -1, 0 }
|
||||||
|
};
|
||||||
|
|
||||||
|
/*
|
||||||
|
* devclass_get_device / device_get_softc could be used
|
||||||
|
* to dynamically locate this, however the timers are a
|
||||||
|
* required device which can't be unloaded so there's
|
||||||
|
* no need for the overhead.
|
||||||
|
*/
|
||||||
|
static struct jz4780_timer_softc *jz4780_timer_sc = NULL;
|
||||||
|
|
||||||
|
#define CSR_WRITE_4(sc, reg, val) bus_write_4((sc)->res[0], reg, (val))
|
||||||
|
#define CSR_READ_4(sc, reg) bus_read_4((sc)->res[0], reg)
|
||||||
|
|
||||||
|
static unsigned
|
||||||
|
jz4780_get_timecount(struct timecounter *tc)
|
||||||
|
{
|
||||||
|
struct jz4780_timer_softc *sc =
|
||||||
|
(struct jz4780_timer_softc *)tc->tc_priv;
|
||||||
|
|
||||||
|
return CSR_READ_4(sc, JZ_OST_CNT_LO);
|
||||||
|
}
|
||||||
|
|
||||||
|
static int
|
||||||
|
jz4780_hardclock(void *arg)
|
||||||
|
{
|
||||||
|
struct jz4780_timer_softc *sc = (struct jz4780_timer_softc *)arg;
|
||||||
|
|
||||||
|
CSR_WRITE_4(sc, JZ_TC_TFCR, TFR_FFLAG5);
|
||||||
|
CSR_WRITE_4(sc, JZ_TC_TECR, TESR_TCST5);
|
||||||
|
|
||||||
|
if (sc->et.et_active)
|
||||||
|
sc->et.et_event_cb(&sc->et, sc->et.et_arg);
|
||||||
|
|
||||||
|
return (FILTER_HANDLED);
|
||||||
|
}
|
||||||
|
|
||||||
|
static int
|
||||||
|
jz4780_timer_start(struct eventtimer *et, sbintime_t first, sbintime_t period)
|
||||||
|
{
|
||||||
|
struct jz4780_timer_softc *sc =
|
||||||
|
(struct jz4780_timer_softc *)et->et_priv;
|
||||||
|
uint32_t ticks;
|
||||||
|
|
||||||
|
ticks = (first * et->et_frequency) / SBT_1S;
|
||||||
|
if (ticks == 0)
|
||||||
|
return (EINVAL);
|
||||||
|
|
||||||
|
CSR_WRITE_4(sc, JZ_TC_TDFR(5), ticks);
|
||||||
|
CSR_WRITE_4(sc, JZ_TC_TCNT(5), 0);
|
||||||
|
CSR_WRITE_4(sc, JZ_TC_TESR, TESR_TCST5);
|
||||||
|
|
||||||
|
return (0);
|
||||||
|
}
|
||||||
|
|
||||||
|
static int
|
||||||
|
jz4780_timer_stop(struct eventtimer *et)
|
||||||
|
{
|
||||||
|
struct jz4780_timer_softc *sc =
|
||||||
|
(struct jz4780_timer_softc *)et->et_priv;
|
||||||
|
|
||||||
|
CSR_WRITE_4(sc, JZ_TC_TECR, TESR_TCST5);
|
||||||
|
return (0);
|
||||||
|
}
|
||||||
|
|
||||||
|
static int
|
||||||
|
jz4780_timer_probe(device_t dev)
|
||||||
|
{
|
||||||
|
|
||||||
|
if (!ofw_bus_status_okay(dev))
|
||||||
|
return (ENXIO);
|
||||||
|
|
||||||
|
if (!ofw_bus_is_compatible(dev, "ingenic,jz4780-tcu"))
|
||||||
|
return (ENXIO);
|
||||||
|
|
||||||
|
device_set_desc(dev, "Ingenic JZ4780 timer");
|
||||||
|
|
||||||
|
return (BUS_PROBE_DEFAULT);
|
||||||
|
}
|
||||||
|
|
||||||
|
static int
|
||||||
|
jz4780_timer_attach(device_t dev)
|
||||||
|
{
|
||||||
|
struct jz4780_timer_softc *sc = device_get_softc(dev);
|
||||||
|
pcell_t counter_freq;
|
||||||
|
clk_t clk;
|
||||||
|
|
||||||
|
/* There should be exactly one instance. */
|
||||||
|
if (jz4780_timer_sc != NULL)
|
||||||
|
return (ENXIO);
|
||||||
|
|
||||||
|
sc->dev = dev;
|
||||||
|
|
||||||
|
if (bus_alloc_resources(dev, jz4780_timer_spec, sc->res)) {
|
||||||
|
device_printf(dev, "can not allocate resources for device\n");
|
||||||
|
return (ENXIO);
|
||||||
|
}
|
||||||
|
|
||||||
|
counter_freq = 0;
|
||||||
|
if (clk_get_by_name(dev, "ext", &clk) == 0) {
|
||||||
|
uint64_t clk_freq;
|
||||||
|
|
||||||
|
if (clk_get_freq(clk, &clk_freq) == 0)
|
||||||
|
counter_freq = (uint32_t)clk_freq / 16;
|
||||||
|
clk_release(clk);
|
||||||
|
}
|
||||||
|
if (counter_freq == 0) {
|
||||||
|
device_printf(dev, "unable to determine ext clock frequency\n");
|
||||||
|
/* Hardcode value we 'know' is correct */
|
||||||
|
counter_freq = 48000000 / 16;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Disable the timers, select the input for each timer,
|
||||||
|
* clear and then start OST.
|
||||||
|
*/
|
||||||
|
|
||||||
|
/* Stop OST, if it happens to be running */
|
||||||
|
CSR_WRITE_4(sc, JZ_TC_TECR, TESR_OST);
|
||||||
|
/* Stop all other channels as well */
|
||||||
|
CSR_WRITE_4(sc, JZ_TC_TECR, TESR_TCST0 | TESR_TCST1 | TESR_TCST2 |
|
||||||
|
TESR_TCST3 | TESR_TCST4 | TESR_TCST5 | TESR_TCST6 | TESR_TCST3);
|
||||||
|
/* Clear detect mask flags */
|
||||||
|
CSR_WRITE_4(sc, JZ_TC_TFCR, 0xFFFFFFFF);
|
||||||
|
/* Mask all interrupts */
|
||||||
|
CSR_WRITE_4(sc, JZ_TC_TMSR, 0xFFFFFFFF);
|
||||||
|
|
||||||
|
/* Init counter with known data */
|
||||||
|
CSR_WRITE_4(sc, JZ_OST_CTRL, 0);
|
||||||
|
CSR_WRITE_4(sc, JZ_OST_CNT_LO, 0);
|
||||||
|
CSR_WRITE_4(sc, JZ_OST_CNT_HI, 0);
|
||||||
|
CSR_WRITE_4(sc, JZ_OST_DATA, 0xffffffff);
|
||||||
|
|
||||||
|
/* Configure counter for external clock */
|
||||||
|
CSR_WRITE_4(sc, JZ_OST_CTRL, OSTC_EXT_EN | OSTC_MODE | OSTC_DIV_16);
|
||||||
|
|
||||||
|
/* Start the counter again */
|
||||||
|
CSR_WRITE_4(sc, JZ_TC_TESR, TESR_OST);
|
||||||
|
|
||||||
|
/* Configure TCU channel 5 similarly to OST and leave it disabled */
|
||||||
|
CSR_WRITE_4(sc, JZ_TC_TCSR(5), TCSR_EXT_EN | TCSR_DIV_16);
|
||||||
|
CSR_WRITE_4(sc, JZ_TC_TMCR, TMR_FMASK(5));
|
||||||
|
|
||||||
|
if (bus_setup_intr(dev, sc->res[2], INTR_TYPE_CLK,
|
||||||
|
jz4780_hardclock, NULL, sc, &sc->ih_cookie)) {
|
||||||
|
device_printf(dev, "could not setup interrupt handler\n");
|
||||||
|
bus_release_resources(dev, jz4780_timer_spec, sc->res);
|
||||||
|
return (ENXIO);
|
||||||
|
}
|
||||||
|
|
||||||
|
sc->et.et_name = "JZ4780 TCU5";
|
||||||
|
sc->et.et_flags = ET_FLAGS_ONESHOT;
|
||||||
|
sc->et.et_frequency = counter_freq;
|
||||||
|
sc->et.et_quality = 1000;
|
||||||
|
sc->et.et_min_period = (0x00000002LLU * SBT_1S) / sc->et.et_frequency;
|
||||||
|
sc->et.et_max_period = (0x0000fffeLLU * SBT_1S) / sc->et.et_frequency;
|
||||||
|
sc->et.et_start = jz4780_timer_start;
|
||||||
|
sc->et.et_stop = jz4780_timer_stop;
|
||||||
|
sc->et.et_priv = sc;
|
||||||
|
|
||||||
|
et_register(&sc->et);
|
||||||
|
|
||||||
|
sc->tc.tc_get_timecount = jz4780_get_timecount;
|
||||||
|
sc->tc.tc_name = "JZ4780 OST";
|
||||||
|
sc->tc.tc_frequency = counter_freq;
|
||||||
|
sc->tc.tc_counter_mask = ~0u;
|
||||||
|
sc->tc.tc_quality = 1000;
|
||||||
|
sc->tc.tc_priv = sc;
|
||||||
|
|
||||||
|
tc_init(&sc->tc);
|
||||||
|
|
||||||
|
/* Now when tc is initialized, allow DELAY to find it */
|
||||||
|
jz4780_timer_sc = sc;
|
||||||
|
|
||||||
|
return (0);
|
||||||
|
}
|
||||||
|
|
||||||
|
static int
|
||||||
|
jz4780_timer_detach(device_t dev)
|
||||||
|
{
|
||||||
|
|
||||||
|
return (EBUSY);
|
||||||
|
}
|
||||||
|
|
||||||
|
static device_method_t jz4780_timer_methods[] = {
|
||||||
|
/* Device interface */
|
||||||
|
DEVMETHOD(device_probe, jz4780_timer_probe),
|
||||||
|
DEVMETHOD(device_attach, jz4780_timer_attach),
|
||||||
|
DEVMETHOD(device_detach, jz4780_timer_detach),
|
||||||
|
|
||||||
|
DEVMETHOD_END
|
||||||
|
};
|
||||||
|
|
||||||
|
static driver_t jz4780_timer_driver = {
|
||||||
|
"timer",
|
||||||
|
jz4780_timer_methods,
|
||||||
|
sizeof(struct jz4780_timer_softc),
|
||||||
|
};
|
||||||
|
|
||||||
|
static devclass_t jz4780_timer_devclass;
|
||||||
|
|
||||||
|
EARLY_DRIVER_MODULE(timer, simplebus, jz4780_timer_driver,
|
||||||
|
jz4780_timer_devclass, 0, 0, BUS_PASS_TIMER);
|
||||||
|
|
||||||
|
void
|
||||||
|
DELAY(int usec)
|
||||||
|
{
|
||||||
|
uint32_t counter;
|
||||||
|
uint32_t delta, now, previous, remaining;
|
||||||
|
|
||||||
|
/* Timer has not yet been initialized */
|
||||||
|
if (jz4780_timer_sc == NULL) {
|
||||||
|
for (; usec > 0; usec--)
|
||||||
|
for (counter = 200; counter > 0; counter--) {
|
||||||
|
/* Prevent gcc from optimizing out the loop */
|
||||||
|
mips_rd_cause();
|
||||||
|
}
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Some of the other timers in the source tree do this calculation as:
|
||||||
|
*
|
||||||
|
* usec * ((sc->tc.tc_frequency / 1000000) + 1)
|
||||||
|
*
|
||||||
|
* which gives a fairly pessimistic result when tc_frequency is an exact
|
||||||
|
* multiple of 1000000. Given the data type and typical values for
|
||||||
|
* tc_frequency adding 999999 shouldn't overflow.
|
||||||
|
*/
|
||||||
|
remaining = usec * ((jz4780_timer_sc->tc.tc_frequency + 999999) /
|
||||||
|
1000000);
|
||||||
|
|
||||||
|
/*
|
||||||
|
* We add one since the first iteration may catch the counter just
|
||||||
|
* as it is changing.
|
||||||
|
*/
|
||||||
|
remaining += 1;
|
||||||
|
|
||||||
|
previous = jz4780_get_timecount(&jz4780_timer_sc->tc);
|
||||||
|
|
||||||
|
for ( ; ; ) {
|
||||||
|
now = jz4780_get_timecount(&jz4780_timer_sc->tc);
|
||||||
|
|
||||||
|
/*
|
||||||
|
* If the timer has rolled over, then we have the case:
|
||||||
|
*
|
||||||
|
* if (previous > now) {
|
||||||
|
* delta = (0 - previous) + now
|
||||||
|
* }
|
||||||
|
*
|
||||||
|
* which is really no different then the normal case.
|
||||||
|
* Both cases are simply:
|
||||||
|
*
|
||||||
|
* delta = now - previous.
|
||||||
|
*/
|
||||||
|
delta = now - previous;
|
||||||
|
|
||||||
|
if (delta >= remaining)
|
||||||
|
break;
|
||||||
|
|
||||||
|
previous = now;
|
||||||
|
remaining -= delta;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
platform_initclocks(void)
|
||||||
|
{
|
||||||
|
|
||||||
|
}
|
||||||
|
|
220
sys/mips/ingenic/jz4780_uart.c
Normal file
220
sys/mips/ingenic/jz4780_uart.c
Normal file
@ -0,0 +1,220 @@
|
|||||||
|
/*-
|
||||||
|
* 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 <sys/cdefs.h>
|
||||||
|
__FBSDID("$FreeBSD$");
|
||||||
|
|
||||||
|
#include <sys/param.h>
|
||||||
|
#include <sys/systm.h>
|
||||||
|
#include <sys/bus.h>
|
||||||
|
#include <sys/conf.h>
|
||||||
|
#include <sys/kernel.h>
|
||||||
|
#include <sys/module.h>
|
||||||
|
#include <sys/sysctl.h>
|
||||||
|
#include <machine/bus.h>
|
||||||
|
|
||||||
|
#include <dev/extres/clk/clk.h>
|
||||||
|
#include <dev/fdt/fdt_common.h>
|
||||||
|
#include <dev/ofw/ofw_bus.h>
|
||||||
|
#include <dev/ofw/ofw_bus_subr.h>
|
||||||
|
#include <dev/uart/uart.h>
|
||||||
|
#include <dev/uart/uart_cpu.h>
|
||||||
|
#include <dev/uart/uart_cpu_fdt.h>
|
||||||
|
#include <dev/uart/uart_bus.h>
|
||||||
|
#include <dev/uart/uart_dev_ns8250.h>
|
||||||
|
#include <dev/ic/ns16550.h>
|
||||||
|
#include "uart_if.h"
|
||||||
|
|
||||||
|
/*
|
||||||
|
* High-level UART interface.
|
||||||
|
*/
|
||||||
|
struct jz4780_uart_softc {
|
||||||
|
struct ns8250_softc ns8250_base;
|
||||||
|
clk_t clk_mod;
|
||||||
|
clk_t clk_baud;
|
||||||
|
};
|
||||||
|
|
||||||
|
static int
|
||||||
|
jz4780_bus_attach(struct uart_softc *sc)
|
||||||
|
{
|
||||||
|
struct ns8250_softc *ns8250;
|
||||||
|
struct uart_bas *bas;
|
||||||
|
int rv;
|
||||||
|
|
||||||
|
ns8250 = (struct ns8250_softc *)sc;
|
||||||
|
bas = &sc->sc_bas;
|
||||||
|
|
||||||
|
rv = ns8250_bus_attach(sc);
|
||||||
|
if (rv != 0)
|
||||||
|
return (0);
|
||||||
|
|
||||||
|
/* Configure uart to use extra IER_RXTMOUT bit */
|
||||||
|
ns8250->ier_rxbits = IER_RXTMOUT | IER_EMSC | IER_ERLS | IER_ERXRDY;
|
||||||
|
ns8250->ier_mask = ~(ns8250->ier_rxbits);
|
||||||
|
ns8250->ier = uart_getreg(bas, REG_IER) & ns8250->ier_mask;
|
||||||
|
ns8250->ier |= ns8250->ier_rxbits;
|
||||||
|
uart_setreg(bas, REG_IER, ns8250->ier);
|
||||||
|
uart_barrier(bas);
|
||||||
|
return (0);
|
||||||
|
}
|
||||||
|
|
||||||
|
static kobj_method_t jz4780_uart_methods[] = {
|
||||||
|
KOBJMETHOD(uart_probe, ns8250_bus_probe),
|
||||||
|
KOBJMETHOD(uart_attach, jz4780_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(uart_grab, ns8250_bus_grab),
|
||||||
|
KOBJMETHOD(uart_ungrab, ns8250_bus_ungrab),
|
||||||
|
KOBJMETHOD_END
|
||||||
|
};
|
||||||
|
|
||||||
|
static struct uart_class jz4780_uart_class = {
|
||||||
|
"jz4780_uart_class",
|
||||||
|
jz4780_uart_methods,
|
||||||
|
sizeof(struct jz4780_uart_softc),
|
||||||
|
.uc_ops = &uart_ns8250_ops,
|
||||||
|
.uc_range = 8,
|
||||||
|
.uc_rclk = 0,
|
||||||
|
};
|
||||||
|
|
||||||
|
/* Compatible devices. */
|
||||||
|
static struct ofw_compat_data compat_data[] = {
|
||||||
|
{"ingenic,jz4780-uart", (uintptr_t)&jz4780_uart_class},
|
||||||
|
{NULL, (uintptr_t)NULL},
|
||||||
|
};
|
||||||
|
|
||||||
|
UART_FDT_CLASS(compat_data);
|
||||||
|
|
||||||
|
/*
|
||||||
|
* UART Driver interface.
|
||||||
|
*/
|
||||||
|
static int
|
||||||
|
jz4780_uart_get_shift(device_t dev)
|
||||||
|
{
|
||||||
|
phandle_t node;
|
||||||
|
pcell_t shift;
|
||||||
|
|
||||||
|
node = ofw_bus_get_node(dev);
|
||||||
|
if ((OF_getencprop(node, "reg-shift", &shift, sizeof(shift))) <= 0)
|
||||||
|
shift = 2;
|
||||||
|
return ((int)shift);
|
||||||
|
}
|
||||||
|
|
||||||
|
static int
|
||||||
|
jz4780_uart_probe(device_t dev)
|
||||||
|
{
|
||||||
|
struct jz4780_uart_softc *sc;
|
||||||
|
uint64_t freq;
|
||||||
|
int shift;
|
||||||
|
int rv;
|
||||||
|
const struct ofw_compat_data *cd;
|
||||||
|
|
||||||
|
sc = device_get_softc(dev);
|
||||||
|
if (!ofw_bus_status_okay(dev))
|
||||||
|
return (ENXIO);
|
||||||
|
cd = ofw_bus_search_compatible(dev, compat_data);
|
||||||
|
if (cd->ocd_data == 0)
|
||||||
|
return (ENXIO);
|
||||||
|
|
||||||
|
/* Figure out clock setup */
|
||||||
|
rv = clk_get_by_ofw_name(dev, 0, "module", &sc->clk_mod);
|
||||||
|
if (rv != 0) {
|
||||||
|
device_printf(dev, "Cannot get UART clock: %d\n", rv);
|
||||||
|
return (ENXIO);
|
||||||
|
}
|
||||||
|
rv = clk_enable(sc->clk_mod);
|
||||||
|
if (rv != 0) {
|
||||||
|
device_printf(dev, "Cannot enable UART clock: %d\n", rv);
|
||||||
|
return (ENXIO);
|
||||||
|
}
|
||||||
|
rv = clk_get_by_ofw_name(dev, 0, "baud", &sc->clk_baud);
|
||||||
|
if (rv != 0) {
|
||||||
|
device_printf(dev, "Cannot get UART clock: %d\n", rv);
|
||||||
|
return (ENXIO);
|
||||||
|
}
|
||||||
|
rv = clk_enable(sc->clk_baud);
|
||||||
|
if (rv != 0) {
|
||||||
|
device_printf(dev, "Cannot enable UART clock: %d\n", rv);
|
||||||
|
return (ENXIO);
|
||||||
|
}
|
||||||
|
rv = clk_get_freq(sc->clk_baud, &freq);
|
||||||
|
if (rv != 0) {
|
||||||
|
device_printf(dev, "Cannot determine UART clock frequency: %d\n", rv);
|
||||||
|
return (ENXIO);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (bootverbose)
|
||||||
|
device_printf(dev, "got UART clock: %lld\n", freq);
|
||||||
|
sc->ns8250_base.base.sc_class = (struct uart_class *)cd->ocd_data;
|
||||||
|
shift = jz4780_uart_get_shift(dev);
|
||||||
|
return (uart_bus_probe(dev, shift, (int)freq, 0, 0));
|
||||||
|
}
|
||||||
|
|
||||||
|
static int
|
||||||
|
jz4780_uart_detach(device_t dev)
|
||||||
|
{
|
||||||
|
struct jz4780_uart_softc *sc;
|
||||||
|
int rv;
|
||||||
|
|
||||||
|
rv = uart_bus_detach(dev);
|
||||||
|
if (rv != 0)
|
||||||
|
return (rv);
|
||||||
|
|
||||||
|
sc = device_get_softc(dev);
|
||||||
|
if (sc->clk_mod != NULL) {
|
||||||
|
clk_release(sc->clk_mod);
|
||||||
|
}
|
||||||
|
if (sc->clk_baud != NULL) {
|
||||||
|
clk_release(sc->clk_baud);
|
||||||
|
}
|
||||||
|
return (0);
|
||||||
|
}
|
||||||
|
|
||||||
|
static device_method_t jz4780_uart_bus_methods[] = {
|
||||||
|
/* Device interface */
|
||||||
|
DEVMETHOD(device_probe, jz4780_uart_probe),
|
||||||
|
DEVMETHOD(device_attach, uart_bus_attach),
|
||||||
|
DEVMETHOD(device_detach, jz4780_uart_detach),
|
||||||
|
{ 0, 0 }
|
||||||
|
};
|
||||||
|
|
||||||
|
static driver_t jz4780_uart_driver = {
|
||||||
|
uart_driver_name,
|
||||||
|
jz4780_uart_bus_methods,
|
||||||
|
sizeof(struct jz4780_uart_softc),
|
||||||
|
};
|
||||||
|
|
||||||
|
DRIVER_MODULE(jz4780_uart, simplebus, jz4780_uart_driver, uart_devclass,
|
||||||
|
0, 0);
|
Loading…
Reference in New Issue
Block a user