? sys/arch/arm/omap/omap_dmtimer_obio.c Index: sys/arch/evbarm/conf/BEAGLEBONE =================================================================== RCS file: /cvsroot/src/sys/arch/evbarm/conf/BEAGLEBONE,v retrieving revision 1.3 diff -p -u -r1.3 BEAGLEBONE --- sys/arch/evbarm/conf/BEAGLEBONE 17 Oct 2012 14:48:11 -0000 1.3 +++ sys/arch/evbarm/conf/BEAGLEBONE 11 Dec 2012 08:50:54 -0000 @@ -21,6 +21,9 @@ options CPU_CORTEXA8 options TI_AM335X options PMAPCOUNTERS +# XXX The Cortex PMC delay() doesn't seem to work. +#no options CORTEX_PMC + # Architecture options #makeoptions CPUFLAGS+="-mthumb" @@ -132,7 +135,7 @@ options KTRACE # system call tracing, #options PERFCTRS # performance counters options DIAGNOSTIC # internally consistency checks -#options DEBUG +options DEBUG #options PMAP_DEBUG # Enable pmap_debug_level code #options IPKDB # remote kernel debugging #options VERBOSE_INIT_ARM # verbose bootstraping messages @@ -158,7 +161,7 @@ options UHUB_DEBUG # memorydisk= Set memorydisk size to KB # quiet Show aprint_naive output # verbose Show aprint_normal and aprint_verbose output -options BOOT_ARGS="\"\"" +options BOOT_ARGS="\"-d -v\"" config netbsd root on ? type ? @@ -172,34 +175,45 @@ cpu0 at mainbus? options MEMSIZE=256 # L3 Interconnect -L3i0 at mainbus? +#L3i0 at mainbus? # OBIO -obio0 at mainbus? base 0x48000000 size 0x1000000 # L4 CORE -obio1 at mainbus? base 0x48300000 size 0x0040000 # L4 WAKEUP -obio2 at mainbus? base 0x49000000 size 0x0100000 # L4 PERIPHERAL -#obio3 at mainbus? base 0x54000000 size 0x0800000 # L4 EMUL +obio0 at mainbus? base 0x44000000 size 0x0c000000 +#obio0 at mainbus? base 0x44c00000 size 0x00400000 # L4_WKUP +#obio1 at mainbus? base 0x48000000 size 0x01000000 # L4_PER +#obio2 at mainbus? base 0x4a000000 size 0x01000000 # L4_FAST + + # General Purpose Memory Controller -gpmc0 at mainbus? base 0x6e000000 +gpmc0 at mainbus? base 0x50000000 + +# Interrupt Controller +omapicu0 at obio0 addr 0x48200000 size 0x1000 intrbase 0 + +# Power, Reset and Clock Management +prcm0 at obio0 addr 0x44e00000 size 0x2000 # PRM Module # SDHC controllers -sdhc0 at obio0 addr 0x4809C000 size 0x0400 intr 83 -#sdhc1 at obio0 addr 0x480B4000 size 0x0400 intr 86 -#sdhc2 at obio0 addr 0x480AD000 size 0x0400 intr 94 +# XXX Kludge -- the am335x's mmc registers start at an offset of #x100 +# from other omap3. (What about omap4?) Need to adapt the omap sdhc +# driver to handle this. +sdhc0 at obio0 addr 0x48060100 size 0x0f00 intr 64 +#sdhc1 at obio0 addr 0x481d8100 size 0x0f00 intr 28 +#sdhc2 at obio0 addr 0x47810100 size 0xff00 intr 29 sdmmc* at sdhc? # SD/MMC bus ld* at sdmmc? +#options SDMMC_DEBUG +#options SDHC_DEBUG -# Interrupt Controller -omapicu0 at obio0 addr 0x48200000 size 0x1000 intrbase 0 -omapgpio0 at obio1 addr 0x48310000 size 0x0400 intrbase 96 intr 29 -#omapgpio1 at obio2 addr 0x49050000 size 0x0400 intrbase 128 intr 30 -#omapgpio2 at obio2 addr 0x49052000 size 0x0400 intrbase 160 intr 31 -#omapgpio3 at obio2 addr 0x49054000 size 0x0400 intrbase 192 intr 32 -omapgpio4 at obio2 addr 0x49056000 size 0x0400 intrbase 224 intr 33 -#omapgpio5 at obio2 addr 0x49058000 size 0x0400 intrbase 256 intr 34 +# General-purpose I/O pins +# XXX These are the GPIO v2 in the AM335x, not v1 as in the OMAP35xx. +#omapgpio0 at obio0 addr 0x44e07000 size 0x1000 intrbase 128 intr 29 +#omapgpio1 at obio0 addr 0x4804c000 size 0x1000 intrbase 160 intr 30 +#omapgpio2 at obio0 addr 0x481ac000 size 0x1000 intrbase 192 intr 32 +#omapgpio3 at obio0 addr 0x481ae000 size 0x1000 intrbase 224 intr 32 -gpio* at omapgpio? +#gpio* at omapgpio? # # I2C Controller # omapi2c0 at tipb? addr 0xfffb3800 intr 36 mult 4 @@ -211,21 +225,27 @@ gpio* at omapgpio? # options I2C_HIGH_TIME_nSEC=1000 # On-board 16550 UARTs -com0 at obio2 addr 0x44e09000 intr 74 mult 4 # UART3 (console) +com0 at obio0 addr 0x44e09000 size 0x1000 intr 72 mult 4 # UART0 options CONSADDR=0x44e09000, CONSPEED=115200 -# Operating System Timer -omapmputmr0 at obio2 addr 0x49032000 intr 38 # GP Timer 2 -# Statistics Timer -omapmputmr1 at obio2 addr 0x49034000 intr 39 # GP Timer 3 -# Microtime Reference Timer -omapmputmr2 at obio2 addr 0x49036000 intr 40 # GP Timer 4 -options OMAP_MPU_TIMER_CLOCK_FREQ=12000000 +# XXX Clock assignment is kinda random. My DM timer 3 seems to be +# unhappy and I don't know why. DM timer 0 doesn't seem to deliver +# interrupts for the hard clock, although it seems to be the obvious +# choice. + +# Hardclock timer +omapdmtimer0 at obio0 addr 0x48040000 size 0x1000 intr 68 # DM Timer 2 + +# Time counter +omapdmtimer1 at obio0 addr 0x44e31000 size 0x1000 intr 67 # DM Timer 1ms + +# Statclock timer +omapdmtimer2 at obio0 addr 0x48044000 size 0x1000 intr 92 # DM Timer 4 + +options OMAP_SYSTEM_CLOCK_FREQ=24000000 # Watchdog timers -omapwdt32k* at obio2 addr 0x49030000 size 2048 # WDT3 -#omapwdt32k* at obio1 addr 0x4830c000 size 2048 # WDT1 -#omapwdt32k* at obio1 addr 0x48314000 size 2048 # WDT2 +#omapwdt32k* at obio0 addr 0x44e35000 size 0x1000 # WDT1 # onboard video #omapfb* at obio0 addr 0x48050000 size 0x10000 @@ -250,9 +270,6 @@ omapwdt32k* at obio2 addr 0x49030000 siz pseudo-device wsmux # mouse & keyboard multiplexor pseudo-device wsfont -# Power, Reset and Clock Management -prcm* at obio1 addr 0x48306000 size 0x2000 # PRM Module - # On-board USB #ehci* at obio0 addr 0x48064800 size 0x0400 intr 77 #ohci* at obio0 addr 0x48064400 size 0x0400 intr 76 @@ -279,7 +296,7 @@ options OMAP_CK_REF_SPEED=12000000 # Pseudo-Devices # disk/mass storage pseudo-devices -pseudo-device md # memory disk device (ramdisk) +#pseudo-device md # memory disk device (ramdisk) #pseudo-device vnd # disk-like interface to files #pseudo-device fss # file system snapshot device #pseudo-device putter # for puffs and pud Index: sys/arch/evbarm/beagle/beagle_machdep.c =================================================================== RCS file: /cvsroot/src/sys/arch/evbarm/beagle/beagle_machdep.c,v retrieving revision 1.22 diff -p -u -r1.22 beagle_machdep.c --- sys/arch/evbarm/beagle/beagle_machdep.c 5 Sep 2012 00:06:21 -0000 1.22 +++ sys/arch/evbarm/beagle/beagle_machdep.c 11 Dec 2012 08:50:54 -0000 @@ -173,6 +173,9 @@ __KERNEL_RCSID(0, "$NetBSD: beagle_machd #include #include #include +#ifdef TI_AM335X +# include +#endif #include #include @@ -213,6 +216,9 @@ static void omap3_cpu_clk(void); #if defined(OMAP_4430) static void omap4_cpu_clk(void); #endif +#if defined(TI_AM335X) +static void am335x_cpu_clk(void); +#endif bs_protos(bs_notimpl); @@ -375,6 +381,9 @@ initarm(void *arg) #if defined(OMAP_4430) omap4_cpu_clk(); // find our CPU speed. #endif +#if defined(TI_AM335X) + am335x_cpu_clk(); +#endif /* Heads up ... Setup the CPU / MMU / TLB functions. */ if (set_cpufuncs()) panic("cpu not recognized!"); @@ -589,6 +598,26 @@ omap4_cpu_clk(void) } #endif /* OMAP_4400 */ +#if defined(TI_AM335X) +void +am335x_cpu_clk(void) +{ + const vaddr_t cm_base = OMAP2_CM_BASE - OMAP_L4_CORE_BASE + OMAP_L4_CORE_VBASE; + const vaddr_t cm_wkup_base = cm_base + AM335X_PRCM_CM_WKUP; + const uint32_t sys_clk = 24000000; + const uint32_t clksel_dpll_mpu = *(volatile uint32_t *)(cm_wkup_base + TI_AM335X_CM_CLKSEL_DPLL_MPU); + const uint32_t div_m2_dpll_mpu = *(volatile uint32_t *)(cm_wkup_base + TI_AM335X_CM_DIV_M2_DPLL_MPU); + const uint32_t m = __SHIFTOUT(clksel_dpll_mpu, TI_AM335X_CM_CLKSEL_DPLL_MPU_DPLL_MULT); + const uint32_t n = __SHIFTOUT(clksel_dpll_mpu, TI_AM335X_CM_CLKSEL_DPLL_MPU_DPLL_DIV); + const uint32_t m2 = __SHIFTOUT(div_m2_dpll_mpu, TI_AM335X_CM_DIV_M2_DPLL_MPU_DPLL_CLKOUT_DIV); + /* XXX This ignores CM_CLKSEL_DPLL_MPU[DPLL_REGM4XEN]. */ + curcpu()->ci_data.cpu_cc_freq = ((m * (sys_clk / (n + 1))) / m2); + printf("%s: %"PRIu64": sys_clk=%u m=%u n=%u (%u) m2=%u\n", + __func__, curcpu()->ci_data.cpu_cc_freq, + sys_clk, m, n, n+1, m2); +} +#endif + void beagle_device_register(device_t self, void *aux) { Index: sys/arch/arm/omap/am335x_dmtimer.c =================================================================== RCS file: sys/arch/arm/omap/am335x_dmtimer.c diff -N sys/arch/arm/omap/am335x_dmtimer.c --- /dev/null 1 Jan 1970 00:00:00 -0000 +++ sys/arch/arm/omap/am335x_dmtimer.c 11 Dec 2012 08:50:54 -0000 @@ -0,0 +1,144 @@ +/* $NetBSD$ */ + +/* + * TI OMAP Dual-mode timer attachments for AM335x + */ + +/*- + * Copyright (c) 2012 The NetBSD Foundation, Inc. + * All rights reserved. + * + * This code is derived from software contributed to The NetBSD Foundation + * by Taylor R. Campbell. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS + * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED + * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS + * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + */ + +#include +__KERNEL_RCSID(0, "$NetBSD$"); + +#include +#include +#include +#include +#include + +#include + +#include +#include + +#ifndef STATHZ +# define STATHZ 97 +#endif + +struct am335x_dmtimer { + const char *ad_name; + unsigned int ad_version; + bus_addr_t ad_base_addr; + int ad_intr; + struct omap_module ad_module; +}; + +static const struct am335x_dmtimer am335x_dmtimers[] = { + { "DMTIMER0", 2, 0x44e05000, 66, { AM335X_PRCM_CM_WKUP, 0x10 } }, + { "DMTIMER1ms", 1, 0x44e31000, 67, { AM335X_PRCM_CM_WKUP, 0xc4 } }, + { "DMTIMER2", 2, 0x48040000, 68, { AM335X_PRCM_CM_PER, 0x80 } }, + { "DMTIMER3", 2, 0x48042000, 69, { AM335X_PRCM_CM_PER, 0x84 } }, + { "DMTIMER4", 2, 0x48044000, 92, { AM335X_PRCM_CM_PER, 0x88 } }, + { "DMTIMER5", 2, 0x48046000, 93, { AM335X_PRCM_CM_PER, 0xec } }, + { "DMTIMER6", 2, 0x48048000, 94, { AM335X_PRCM_CM_PER, 0xf0 } }, + { "DMTIMER7", 2, 0x4804a000, 95, { AM335X_PRCM_CM_PER, 0x7c } }, +}; + +static int am335x_dmtimer_match(device_t, cfdata_t, void *); +static void am335x_dmtimer_attach(device_t, device_t, void *); + +CFATTACH_DECL_NEW(omap_dmtimer_obio, sizeof(struct omap_dmtimer_softc), + am335x_dmtimer_match, am335x_dmtimer_attach, NULL, NULL); + +static int +am335x_dmtimer_match(device_t parent, cfdata_t match, void *aux) +{ + struct obio_attach_args *obio = aux; + size_t i; + + if (obio->obio_size != 0x1000) + return 0; + + for (i = 0; i < __arraycount(am335x_dmtimers); i++) + if ((obio->obio_addr == am335x_dmtimers[i].ad_base_addr) && + (obio->obio_intr == am335x_dmtimers[i].ad_intr)) + return 1; + + return 0; +} + +static void +am335x_dmtimer_attach(device_t parent, device_t self, void *aux) +{ + struct omap_dmtimer_softc *sc = device_private(self); + struct obio_attach_args *obio = aux; + const struct am335x_dmtimer *ad = NULL; + size_t i; + + for (i = 0; i < __arraycount(am335x_dmtimers); i++) + if ((obio->obio_addr == am335x_dmtimers[i].ad_base_addr) && + (obio->obio_intr == am335x_dmtimers[i].ad_intr)) { + ad = &am335x_dmtimers[i]; + break; + } + + KASSERT(ad != NULL); + aprint_normal(": %s\n", ad->ad_name); + + sc->sc_dev = self; + sc->sc_module = &ad->ad_module; + sc->sc_version = ad->ad_version; + sc->sc_intr = ad->ad_intr; + sc->sc_iot = obio->obio_iot; + + KASSERT(obio->obio_size == 0x1000); + if (bus_space_map(obio->obio_iot, obio->obio_addr, obio->obio_size, 0, + &sc->sc_ioh) != 0) + panic("%s: unable to map bus space", device_xname(self)); + + /* XXX Crock. */ + switch (device_unit(self)) { + case 0: + omap_dmtimer_attach_hardclock(sc); + break; + + case 1: + omap_dmtimer_attach_timecounter(sc); + break; + + case 2: + KASSERT(stathz == 0); + profhz = stathz = STATHZ; + omap_dmtimer_attach_statclock(sc); + break; + + default: + panic("%s: but what am I to do?", device_xname(self)); + } +} Index: sys/arch/arm/omap/am335x_prcm.c =================================================================== RCS file: sys/arch/arm/omap/am335x_prcm.c diff -N sys/arch/arm/omap/am335x_prcm.c --- /dev/null 1 Jan 1970 00:00:00 -0000 +++ sys/arch/arm/omap/am335x_prcm.c 11 Dec 2012 08:50:54 -0000 @@ -0,0 +1,95 @@ +/* $NetBSD$ */ + +/* + * TI OMAP Power, Reset, and Clock Management on the AM335x + */ + +/*- + * Copyright (c) 2012 The NetBSD Foundation, Inc. + * All rights reserved. + * + * This code is derived from software contributed to The NetBSD Foundation + * by Taylor R. Campbell. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS + * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED + * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS + * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + */ + +#include +__KERNEL_RCSID(0, "$NetBSD$"); + +#include +#include + +#include +#include + +#define AM335X_CLKCTRL_MODULEMODE_MASK __BITS(0, 1) +#define AM335X_CLKCTRL_MODULEMODE_DISABLED 0 +#define AM335X_CLKCTRL_MODULEMODE_ENABLE 2 + +static void +am335x_prcm_check_clkctrl(bus_size_t cm_module, + bus_size_t clkctrl_reg, uint32_t v) +{ +#ifdef DIAGNOSTIC + uint32_t u = prcm_read_4(cm_module, clkctrl_reg); + + if (__SHIFTOUT(u, AM335X_CLKCTRL_MODULEMODE_MASK) != + __SHIFTOUT(v, AM335X_CLKCTRL_MODULEMODE_MASK)) + aprint_error("clkctrl didn't take: %"PRIx32" -/-> %"PRIx32"\n", + u, v); +#else + (void)cm_module; + (void)clkctrl_reg; + (void)v; +#endif +} + +void +prcm_module_enable(const struct omap_module *om) +{ + bus_size_t cm_module = om->om_prcm_cm_module; + bus_size_t clkctrl_reg = om->om_prcm_cm_clkctrl_reg; + uint32_t clkctrl; + + clkctrl = prcm_read_4(cm_module, clkctrl_reg); + clkctrl &=~ AM335X_CLKCTRL_MODULEMODE_MASK; + clkctrl |= __SHIFTIN(AM335X_CLKCTRL_MODULEMODE_ENABLE, + AM335X_CLKCTRL_MODULEMODE_MASK); + prcm_write_4(cm_module, clkctrl_reg, clkctrl); + am335x_prcm_check_clkctrl(cm_module, clkctrl_reg, clkctrl); +} + +void +prcm_module_disable(const struct omap_module *om) +{ + bus_size_t cm_module = om->om_prcm_cm_module; + bus_size_t clkctrl_reg = om->om_prcm_cm_clkctrl_reg; + uint32_t clkctrl; + + clkctrl = prcm_read_4(cm_module, clkctrl_reg); + clkctrl &=~ AM335X_CLKCTRL_MODULEMODE_MASK; + clkctrl |= __SHIFTIN(AM335X_CLKCTRL_MODULEMODE_DISABLED, + AM335X_CLKCTRL_MODULEMODE_MASK); + prcm_write_4(cm_module, clkctrl_reg, clkctrl); + am335x_prcm_check_clkctrl(cm_module, clkctrl_reg, clkctrl); +} Index: sys/arch/arm/omap/am335x_prcm.h =================================================================== RCS file: sys/arch/arm/omap/am335x_prcm.h diff -N sys/arch/arm/omap/am335x_prcm.h --- /dev/null 1 Jan 1970 00:00:00 -0000 +++ sys/arch/arm/omap/am335x_prcm.h 11 Dec 2012 08:50:54 -0000 @@ -0,0 +1,64 @@ +/* $NetBSD$ */ + +/* + * TI OMAP Power, Reset, and Clock Management on the AM335x + */ + +/*- + * Copyright (c) 2012 The NetBSD Foundation, Inc. + * All rights reserved. + * + * This code is derived from software contributed to The NetBSD Foundation + * by Taylor R. Campbell. + * + * 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. + */ + +#ifndef _ARM_OMAP_AM335X_PRCM_H_ +#define _ARM_OMAP_AM335X_PRCM_H_ + +#include + +struct omap_module { + bus_size_t om_prcm_cm_module; + bus_size_t om_prcm_cm_clkctrl_reg; +}; + +#define AM335X_PRCM_CM_PER 0x0000 +#define AM335X_PRCM_CM_WKUP 0x0400 +#define AM335X_PRCM_CM_DPLL 0x0500 +#define AM335X_PRCM_CM_MPU 0x0600 +#define AM335X_PRCM_CM_DEVICE 0x0700 +#define AM335X_PRCM_CM_RTC 0x0800 +#define AM335X_PRCM_CM_GFX 0x0900 +#define AM335X_PRCM_CM_CEFUSE 0x0a00 + +#define AM335X_PRCM_PRM_IRQ 0x0b00 +#define AM335X_PRCM_PRM_PER 0x0c00 +#define AM335X_PRCM_PRM_WKUP 0x0d00 +#define AM335X_PRCM_PRM_MPU 0x0e00 +#define AM335X_PRCM_PRM_DEVICE 0x0f00 +#define AM335X_PRCM_PRM_RTC 0x1000 +#define AM335X_PRCM_PRM_GFX 0x1100 +#define AM335X_PRCM_PRM_CEFUSE 0x1200 + +#endif /* _ARM_OMAP_AM335X_PRCM_H_ */ Index: sys/arch/arm/omap/files.omap2 =================================================================== RCS file: /cvsroot/src/sys/arch/arm/omap/files.omap2,v retrieving revision 1.15 diff -p -u -r1.15 files.omap2 --- sys/arch/arm/omap/files.omap2 5 Sep 2012 00:19:59 -0000 1.15 +++ sys/arch/arm/omap/files.omap2 11 Dec 2012 08:50:54 -0000 @@ -47,6 +47,14 @@ device omapgpio: gpiobus attach omapgpio at obio with omap2gpio file arch/arm/omap/omap2_gpio.c (omap2 | omap3) & omapgpio +# OMAP dual-mode timer +device omapdmtimer +file arch/arm/omap/omap_dmtimer.c omapdmtimer +defparam opt_omap.h OMAP_SYSTEM_CLOCK_FREQ + +attach omapdmtimer at obio with omap_dmtimer_obio +file arch/arm/omap/am335x_dmtimer.c ti_am335x & omapdmtimer + # OMAP 2430 General Purpose Timer device omapmputmr file arch/arm/omap/omap2_mputmr.c omapmputmr @@ -97,6 +105,7 @@ file arch/arm/omap/omap2_nand.c omapnan device prcm attach prcm at obio file arch/arm/omap/omap2_prcm.c prcm needs-flag +file arch/arm/omap/am335x_prcm.c ti_am335x # OHCI USB controller attach ohci at obio with obioohci Index: sys/arch/arm/omap/omap2_obio.c =================================================================== RCS file: /cvsroot/src/sys/arch/arm/omap/omap2_obio.c,v retrieving revision 1.14 diff -p -u -r1.14 omap2_obio.c --- sys/arch/arm/omap/omap2_obio.c 5 Sep 2012 00:19:59 -0000 1.14 +++ sys/arch/arm/omap/omap2_obio.c 11 Dec 2012 08:50:54 -0000 @@ -177,6 +177,11 @@ obio_match(device_t parent, cfdata_t mat return 1; #endif +#ifdef TI_AM335X + if (obio_attached == 0) + return 1; +#endif + return 0; } @@ -212,6 +217,9 @@ obio_attach(device_t parent, device_t se else if (mb->mb_iobase == OMAP2_OBIO_3_BASE) obio_attached |= 8; #endif +#ifdef TI_AM335X + obio_attached = 1; +#endif /* * Attach critical devices first. @@ -351,6 +359,10 @@ static const struct { #if 0 { .name = "dmac", .addr = DMAC_BASE, .required = true }, #endif +#if defined(TI_AM335X) + { .name = "omapicu", .addr = 0x48200000, .required = true }, + { .name = "prcm", .addr = 0x44e00000, .required = true }, +#endif }; static void Index: sys/arch/arm/omap/omap2_prcm.c =================================================================== RCS file: /cvsroot/src/sys/arch/arm/omap/omap2_prcm.c,v retrieving revision 1.3 diff -p -u -r1.3 omap2_prcm.c --- sys/arch/arm/omap/omap2_prcm.c 31 Jan 2012 04:31:37 -0000 1.3 +++ sys/arch/arm/omap/omap2_prcm.c 11 Dec 2012 08:50:54 -0000 @@ -77,6 +77,7 @@ prcm_attach(device_t parent, device_t se { struct obio_attach_args *obio = aux; + KASSERT(prcm_sc == NULL); prcm_sc = device_private(self); prcm_sc->sc_dev = self; @@ -84,7 +85,7 @@ prcm_attach(device_t parent, device_t se prcm_sc->sc_base = obio->obio_addr; prcm_sc->sc_size = OMAP2_PRM_SIZE; - + /* map i/o space for PRM */ if (bus_space_map(prcm_sc->sc_iot, prcm_sc->sc_base, prcm_sc->sc_size, 0, &prcm_sc->sc_ioh) != 0) { @@ -95,16 +96,20 @@ prcm_attach(device_t parent, device_t se aprint_normal(": Power, Reset and Clock Management\n"); } -static uint32_t -prcm_read(bus_addr_t module, bus_addr_t reg) -{ +uint32_t +prcm_read_4(bus_size_t module, bus_size_t reg) +{ + + KASSERT(prcm_sc != NULL); return bus_space_read_4(prcm_sc->sc_iot, prcm_sc->sc_ioh, module + reg); } -static void -prcm_write(bus_addr_t module, bus_addr_t reg, uint32_t data) -{ +void +prcm_write_4(bus_size_t module, bus_size_t reg, uint32_t data) +{ + + KASSERT(prcm_sc != NULL); bus_space_write_4(prcm_sc->sc_iot, prcm_sc->sc_ioh, module + reg, data); } @@ -113,10 +118,10 @@ void prcm_cold_reset(void) { uint32_t val; - - val = prcm_read(OMAP3430_GR_MOD, OMAP2_RM_RSTCTRL); + + val = prcm_read_4(OMAP3430_GR_MOD, OMAP2_RM_RSTCTRL); val |= OMAP_RST_DPLL3; - prcm_write(OMAP3430_GR_MOD, OMAP2_RM_RSTCTRL, val); + prcm_write_4(OMAP3430_GR_MOD, OMAP2_RM_RSTCTRL, val); } Index: sys/arch/arm/omap/omap2_prcm.h =================================================================== RCS file: /cvsroot/src/sys/arch/arm/omap/omap2_prcm.h,v retrieving revision 1.1 diff -p -u -r1.1 omap2_prcm.h --- sys/arch/arm/omap/omap2_prcm.h 28 Aug 2010 13:02:32 -0000 1.1 +++ sys/arch/arm/omap/omap2_prcm.h 11 Dec 2012 08:50:54 -0000 @@ -26,9 +26,16 @@ * SUCH DAMAGE. */ -#ifndef _OMAP2_PRCM_H_ -#define _OMAP2_PRCM_H_ +#ifndef _ARM_OMAP_OMAP2_PRCM_H_ +#define _ARM_OMAP_OMAP2_PRCM_H_ -void prcm_cold_reset(void); +struct omap_module; -#endif +uint32_t prcm_read_4(bus_size_t, bus_size_t); +void prcm_write_4(bus_size_t, bus_size_t, uint32_t); +void prcm_cold_reset(void); + +void prcm_module_enable(const struct omap_module *); +void prcm_module_disable(const struct omap_module *); + +#endif /* _ARM_OMAP_OMAP2_PRCM_H_ */ Index: sys/arch/arm/omap/omap2_reg.h =================================================================== RCS file: /cvsroot/src/sys/arch/arm/omap/omap2_reg.h,v retrieving revision 1.11 diff -p -u -r1.11 omap2_reg.h --- sys/arch/arm/omap/omap2_reg.h 5 Sep 2012 00:19:59 -0000 1.11 +++ sys/arch/arm/omap/omap2_reg.h 11 Dec 2012 08:50:55 -0000 @@ -114,7 +114,7 @@ #define OMAP2_CM_BASE (OMAP4430_L4_CORE_BASE + 0x04000) #endif #ifdef TI_AM335X -#define OMAP2_CM_BASE TI_AM335X_L4_WAKEUP_BASE +#define OMAP2_CM_BASE (TI_AM335X_L4_WAKEUP_BASE + 0x200000) #endif #ifdef TI_DM37XX #define OMAP2_CM_BASE 0x48004000 @@ -301,6 +301,18 @@ #define OMAP4_CM_CLKSEL_DPLL_MPU_DPLL_DIV __BITS(6,0) #define OMAP4_CM_DIV_M2_DPLL_MPU_DPLL_CLKOUT_DIV __BITS(4,0) + +#define TI_AM335X_CM_CLKSEL_DPLL_MPU 0x2c +#define TI_AM335X_CM_CLKSEL_DPLL_MPU_DPLL_BYP_CLKSEL __BIT(23) +#define TI_AM335X_CM_CLKSEL_DPLL_MPU_DPLL_MULT __BITS(18,8) +#define TI_AM335X_CM_CLKSEL_DPLL_MPU_DPLL_DIV __BITS(6,0) + +#define TI_AM335X_CM_DIV_M2_DPLL_MPU 0xa8 +#define TI_AM335X_CM_DIV_M2_DPLL_MPU_ST_DPLL_CLKOUT __BIT(9) +#define TI_AM335X_CM_DIV_M2_DPLL_MPU_DPLL_CLKOUT_GATE_CTRL __BIT(8) +#define TI_AM335X_CM_DIV_M2_DPLL_MPU_DPLL_CLKOUT_DIVCHACK __BIT(5) +#define TI_AM335X_CM_DIV_M2_DPLL_MPU_DPLL_CLKOUT_DIV __BITS(4,0) + /* * Power Management registers base, offsets, and size */ Index: sys/arch/arm/omap/omap3_sdhc.c =================================================================== RCS file: /cvsroot/src/sys/arch/arm/omap/omap3_sdhc.c,v retrieving revision 1.2 diff -p -u -r1.2 omap3_sdhc.c --- sys/arch/arm/omap/omap3_sdhc.c 29 Oct 2012 13:30:25 -0000 1.2 +++ sys/arch/arm/omap/omap3_sdhc.c 11 Dec 2012 08:50:55 -0000 @@ -45,6 +45,11 @@ __KERNEL_RCSID(0, "$NetBSD: omap3_sdhc.c #include #include +#ifdef TI_AM335X +# include +# include +#endif + #include #include @@ -72,6 +77,22 @@ struct obiosdhc_softc { void *sc_ih; /* interrupt vectoring */ }; +#ifdef TI_AM335X +struct am335x_sdhc { + const char *as_name; + bus_addr_t as_base_addr; + int as_intr; + struct omap_module as_module; +}; + +static const struct am335x_sdhc am335x_sdhc[] = { + /* XXX All offset by 0x100 because of the am335x's mmc registers. */ + { "MMCHS0", 0x48060100, 64, { AM335X_PRCM_CM_PER, 0x3c } }, + { "MMC1", 0x481d8100, 28, { AM335X_PRCM_CM_PER, 0xf4 } }, + { "MMCHS2", 0x47810100, 29, { AM335X_PRCM_CM_WKUP, 0xf8 } }, +}; +#endif + CFATTACH_DECL_NEW(obiosdhc, sizeof(struct obiosdhc_softc), obiosdhc_match, obiosdhc_attach, obiosdhc_detach, NULL); @@ -81,6 +102,10 @@ obiosdhc_match(device_t parent, cfdata_t #ifdef OMAP_3530 struct obio_attach_args * const oa = aux; #endif +#ifdef TI_AM335X + struct obio_attach_args * const oa = aux; + size_t i; +#endif #ifdef OMAP_3530 if (oa->obio_addr == SDMMC1_BASE_3530 @@ -89,6 +114,13 @@ obiosdhc_match(device_t parent, cfdata_t return 1; #endif +#ifdef TI_AM335X + for (i = 0; i < __arraycount(am335x_sdhc); i++) + if ((oa->obio_addr == am335x_sdhc[i].as_base_addr) && + (oa->obio_intr == am335x_sdhc[i].as_intr)) + return 1; +#endif + return 0; } @@ -97,8 +129,14 @@ obiosdhc_attach(device_t parent, device_ { struct obiosdhc_softc * const sc = device_private(self); struct obio_attach_args * const oa = aux; + int error, timo; +#if 1 //def OMAP_3530 uint32_t clkd, stat; - int error, timo, clksft, n; + int clksft, n; +#endif +#ifdef TI_AM335X + size_t i; +#endif sc->sc.sc_dmat = oa->obio_dmat; sc->sc.sc_dev = self; @@ -115,7 +153,9 @@ obiosdhc_attach(device_t parent, device_ sc->sc.sc_vendor_card_detect = obiosdhc_card_detect; sc->sc_bst = oa->obio_iot; +#if 1 //def OMAP_3530 clksft = ffs(sc->sc.sc_clkmsk) - 1; +#endif error = bus_space_map(sc->sc_bst, oa->obio_addr, oa->obio_size, 0, &sc->sc_bsh); @@ -131,6 +171,17 @@ obiosdhc_attach(device_t parent, device_ aprint_naive(": SDHC controller\n"); aprint_normal(": SDHC controller\n"); +#ifdef TI_AM335X + /* XXX Not really AM335X-specific. */ + for (i = 0; i < __arraycount(am335x_sdhc); i++) + if ((oa->obio_addr == am335x_sdhc[i].as_base_addr) && + (oa->obio_intr == am335x_sdhc[i].as_intr)) { + prcm_module_enable(&am335x_sdhc[i].as_module); + break; + } + KASSERT(i < __arraycount(am335x_sdhc)); +#endif + /* XXXXXX: Turn-on regurator via I2C. */ /* XXXXXX: And enable ICLOCK/FCLOCK. */ @@ -167,6 +218,7 @@ obiosdhc_attach(device_t parent, device_ goto fail; } +#if 1 //def OMAP_3530 /* Set SDVS 1.8v and DTW 1bit mode */ SDHC_WRITE(sc, SDHC_HOST_CTL, SDHC_VOLTAGE_1_8V << (SDHC_VOLTAGE_SHIFT + 8)); @@ -233,6 +285,7 @@ obiosdhc_attach(device_t parent, device_ SDHC_READ(sc, SDHC_CLOCK_CTL) | CLKD(150) << clksft); SDHC_WRITE(sc, SDHC_CLOCK_CTL, SDHC_READ(sc, SDHC_CLOCK_CTL) | SDHC_SDCLK_ENABLE); +#endif /* OMAP_3530 */ return; Index: sys/arch/arm/omap/omap_dmtimer.c =================================================================== RCS file: sys/arch/arm/omap/omap_dmtimer.c diff -N sys/arch/arm/omap/omap_dmtimer.c --- /dev/null 1 Jan 1970 00:00:00 -0000 +++ sys/arch/arm/omap/omap_dmtimer.c 11 Dec 2012 08:50:55 -0000 @@ -0,0 +1,407 @@ +/* $NetBSD$ */ + +/* + * TI OMAP Dual-mode timers + */ + +/*- + * Copyright (c) 2012 The NetBSD Foundation, Inc. + * All rights reserved. + * + * This code is derived from software contributed to The NetBSD Foundation + * by Taylor R. Campbell. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS + * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED + * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS + * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + */ + +#include +__KERNEL_RCSID(0, "$NetBSD$"); + +#include +#include +#include +#include +#include +#include +#include + +#include + +#include +#include +#include + +typedef uint8_t dmt_reg_t; +typedef uint16_t dmt_timer_reg_t; + +static unsigned int + dmt_tc_get_timecount(struct timecounter *); +static int dmt_hardintr(void *); +static int dmt_statintr(void *); +static void dmt_start_periodic_intr(struct omap_dmtimer_softc *, int, + unsigned int, int (*)(void *)); +static void dmt_set_periodic_intr_frequency(struct omap_dmtimer_softc *, + unsigned int); +static void dmt_start_timecounter(struct omap_dmtimer_softc *); +static unsigned int + dmt_get_timecount(struct omap_dmtimer_softc *); +static void dmt_start(struct omap_dmtimer_softc *, unsigned int); +static void dmt_reset(struct omap_dmtimer_softc *); +static void dmt_enable(struct omap_dmtimer_softc *); +static void dmt_intr_enable(struct omap_dmtimer_softc *, uint32_t); +static void dmt_intr_ack(struct omap_dmtimer_softc *, uint32_t); +static uint32_t dmt_timer_read_4(struct omap_dmtimer_softc *, dmt_timer_reg_t); +static void dmt_timer_write_4(struct omap_dmtimer_softc *, dmt_timer_reg_t, + uint32_t); +static void dmt_timer_write_post_wait(struct omap_dmtimer_softc *, + dmt_timer_reg_t); +static uint32_t dmt_read_4(struct omap_dmtimer_softc *, dmt_reg_t); +static void dmt_write_4(struct omap_dmtimer_softc *, dmt_reg_t, uint32_t); + +static struct omap_dmtimer_softc *hardclock_sc; +static struct omap_dmtimer_softc *statclock_sc; +static struct timecounter dmt_timecounter; + +void +omap_dmtimer_attach_timecounter(struct omap_dmtimer_softc *sc) +{ + + if (dmt_timecounter.tc_priv != NULL) + panic("omap dmtimer timecounter already initialized"); + + dmt_timecounter.tc_priv = sc; +} + +static struct timecounter dmt_timecounter = { + .tc_get_timecount = dmt_tc_get_timecount, + .tc_counter_mask = 0xffffffff, /* XXXMAGIC Make sense? */ + .tc_frequency = OMAP_SYSTEM_CLOCK_FREQ, /* XXXPOWER */ + .tc_name = "dmtimer", /* XXX Which one? */ + .tc_quality = 100, /* XXXMAGIC? */ + .tc_priv = NULL, +}; + +static unsigned int +dmt_tc_get_timecount(struct timecounter *tc) +{ + struct omap_dmtimer_softc *sc = tc->tc_priv; + + if (sc == NULL) + panic("uninitialized omap dmtimer timecounter"); + + return dmt_get_timecount(sc); +} + +void +omap_dmtimer_attach_hardclock(struct omap_dmtimer_softc *sc) +{ + + if (hardclock_sc != NULL) + panic("%s: replacing hardclock %s", device_xname(sc->sc_dev), + device_xname(hardclock_sc->sc_dev)); + hardclock_sc = sc; +} + +void +omap_dmtimer_attach_statclock(struct omap_dmtimer_softc *sc) +{ + + KASSERT(stathz != 0); + if (statclock_sc != NULL) + panic("%s: replacing statclock %s", device_xname(sc->sc_dev), + device_xname(statclock_sc->sc_dev)); + statclock_sc = sc; +} + +void +cpu_initclocks(void) +{ + struct omap_dmtimer_softc *timecounter_sc = dmt_timecounter.tc_priv; + + if (hardclock_sc == NULL) + panic("omap dmtimer hardclock not initialized"); + dmt_enable(hardclock_sc); + dmt_start_periodic_intr(hardclock_sc, IPL_CLOCK, hz, &dmt_hardintr); + + if (timecounter_sc == NULL) + panic("omap dmtimer timecounter not initialized"); + dmt_enable(statclock_sc); + dmt_start_periodic_intr(statclock_sc, IPL_HIGH, stathz, &dmt_statintr); + + if (statclock_sc == NULL) + panic("omap dmtimer statclock not initialized"); + dmt_enable(timecounter_sc); + dmt_start_timecounter(timecounter_sc); + tc_init(&dmt_timecounter); +} + +void +setstatclockrate(int rate) +{ + struct omap_dmtimer_softc *sc = statclock_sc; + + if (rate < 0) + panic("I can't run the statistics clock backward!"); + + if (sc == NULL) + panic("There is no statclock timer!\n"); + + dmt_set_periodic_intr_frequency(sc, rate); +} + +static int +dmt_hardintr(void *frame) +{ + struct omap_dmtimer_softc *sc = hardclock_sc; + + KASSERT(sc != NULL); + dmt_intr_ack(sc, OMAP_DMTIMER_INTR_ALL); + hardclock(frame); + + return 1; +} + +static int +dmt_statintr(void *frame) +{ + struct omap_dmtimer_softc *sc = statclock_sc; + + KASSERT(sc != NULL); + dmt_intr_ack(sc, OMAP_DMTIMER_INTR_ALL); + statclock(frame); + + return 1; +} + +static void +dmt_start_periodic_intr(struct omap_dmtimer_softc *sc, int ipl, + unsigned int frequency, int (*func)(void *)) +{ + + dmt_reset(sc); + dmt_start(sc, frequency); + /* + * Null argument means func gets the interrupt frame. For + * whatever reason it's not an option to pass an argument (such + * as sc) and the interrupt frame both, which is why we have + * the global hardclock_sc and statclock_sc. + */ + intr_establish(sc->sc_intr, ipl, IST_LEVEL, func, 0); + dmt_intr_enable(sc, OMAP_DMTIMER_INTR_OVERFLOW); +} + +static void +dmt_set_periodic_intr_frequency(struct omap_dmtimer_softc *sc, + unsigned int frequency) +{ + + dmt_reset(sc); + dmt_start(sc, frequency); + dmt_intr_enable(sc, OMAP_DMTIMER_INTR_OVERFLOW); +} + +static void +dmt_start_timecounter(struct omap_dmtimer_softc *sc) +{ + + /* + * XXXPOWER On reset, the timer uses the system clock. For + * low-power operation, we can configure timers to use less + * frequent clocks, but there's currently no abstraction for + * doing this. + */ + dmt_reset(sc); + dmt_timer_write_4(sc, OMAP_DMTIMER_TIMER_LOAD, 0); + dmt_timer_write_4(sc, OMAP_DMTIMER_TIMER_COUNTER, 0); + dmt_timer_write_4(sc, OMAP_DMTIMER_TIMER_CTRL, + (OMAP_DMTIMER_TIMER_CTRL_START | + OMAP_DMTIMER_TIMER_CTRL_AUTORELOAD)); +} + +static unsigned int +dmt_get_timecount(struct omap_dmtimer_softc *sc) +{ + + return dmt_timer_read_4(sc, OMAP_DMTIMER_TIMER_COUNTER); +} + +static void +dmt_start(struct omap_dmtimer_softc *sc, unsigned int frequency) +{ + uint32_t value; + + /* + * XXXPOWER Should do something clever with prescaling and + * clock selection to save power. + */ + + /* + * XXX The dmtimer doesn't even necessarily run at the system + * clock frequency by default. On the AM335x, the system clock + * frequency is 24 MHz, but dmtimer0 runs at 32 kHz. + */ + value = (0xffffffff - ((OMAP_SYSTEM_CLOCK_FREQ / frequency) - 1)); + + dmt_timer_write_4(sc, OMAP_DMTIMER_TIMER_LOAD, value); + dmt_timer_write_4(sc, OMAP_DMTIMER_TIMER_COUNTER, value); + + dmt_timer_write_4(sc, OMAP_DMTIMER_TIMER_CTRL, + (OMAP_DMTIMER_TIMER_CTRL_START | + OMAP_DMTIMER_TIMER_CTRL_AUTORELOAD)); +} + +static void +dmt_reset(struct omap_dmtimer_softc *sc) +{ + uint32_t reset_mask; + unsigned int tries = 1000; /* XXXMAGIC */ + + if (sc->sc_version == 1) + reset_mask = OMAP_DMTIMER_V1_OCP_CFG_SOFTRESET_MASK; + else + reset_mask = OMAP_DMTIMER_V2_OCP_CFG_SOFTRESET_MASK; + + dmt_write_4(sc, OMAP_DMTIMER_OCP_CFG, reset_mask); + while (dmt_read_4(sc, OMAP_DMTIMER_OCP_CFG) & reset_mask) { + if (--tries == 0) + panic("unable to reset dmtimer %p", sc); + DELAY(10); /* XXXMAGIC */ + } + + /* + * Posted mode is enabled on reset on the OMAP35x but disabled + * on reset on the AM335x, so handle both cases. + * + * XXXPOWER Does enabling this reduce power consumption? + */ + sc->sc_posted = + (0 != (dmt_read_4(sc, OMAP_DMTIMER_TIMER_SYNC_INT_CTRL) + & OMAP_DMTIMER_TIMER_SYNC_INT_CTRL_POSTED)); +} + +static void +dmt_enable(struct omap_dmtimer_softc *sc) +{ + + if (!sc->sc_enabled) { + prcm_module_enable(sc->sc_module); + sc->sc_enabled = 1; + } +} + +static void +dmt_intr_enable(struct omap_dmtimer_softc *sc, uint32_t intr) +{ + + if (sc->sc_version == 1) { + dmt_write_4(sc, OMAP_DMTIMER_V1_INTR_ENABLE, intr); + } else { + dmt_write_4(sc, OMAP_DMTIMER_V2_INTR_ENABLE_CLEAR, + (OMAP_DMTIMER_INTR_ALL &~ intr)); + dmt_write_4(sc, OMAP_DMTIMER_V2_INTR_ENABLE_SET, intr); + } +} + +static void +dmt_intr_ack(struct omap_dmtimer_softc *sc, uint32_t intr) +{ + + if (sc->sc_version == 1) + dmt_write_4(sc, OMAP_DMTIMER_V1_INTR_STATUS, intr); + else + dmt_write_4(sc, OMAP_DMTIMER_V2_INTR_STATUS, intr); +} + +static uint32_t +dmt_timer_read_4(struct omap_dmtimer_softc *sc, dmt_timer_reg_t reg) +{ + dmt_reg_t timer_base; + + if (sc->sc_version == 1) + timer_base = OMAP_DMTIMER_V1_TIMER_REGS; + else + timer_base = OMAP_DMTIMER_V2_TIMER_REGS; + + dmt_timer_write_post_wait(sc, reg); + return dmt_read_4(sc, (timer_base + reg)); +} + +static void +dmt_timer_write_4(struct omap_dmtimer_softc *sc, dmt_timer_reg_t reg, + uint32_t value) +{ + dmt_reg_t timer_base; + + if (sc->sc_version == 1) + timer_base = OMAP_DMTIMER_V1_TIMER_REGS; + else + timer_base = OMAP_DMTIMER_V2_TIMER_REGS; + + dmt_timer_write_post_wait(sc, reg); + dmt_write_4(sc, (timer_base + reg), value); +} + +static void +dmt_timer_write_post_wait(struct omap_dmtimer_softc *sc, dmt_timer_reg_t reg) +{ + dmt_reg_t timer_base; + + if (sc->sc_version == 1) + timer_base = OMAP_DMTIMER_V1_TIMER_REGS; + else + timer_base = OMAP_DMTIMER_V2_TIMER_REGS; + + /* + * Make sure we can read the TWPS (OMAP_DMTIMER_TIMER_WRITE_POST) + * register with vanilla dmt_read_4. + */ + CTASSERT(OMAP_DMTIMER_TIMER_WRITE_POST == + OMAP_DMTIMER_REG_POSTED_INDEX(OMAP_DMTIMER_TIMER_WRITE_POST)); + + if (sc->sc_posted && OMAP_DMTIMER_REG_POSTED_P(reg)) { + unsigned int tries = 1000; /* XXXMAGIC */ + const dmt_reg_t write_post_reg = (timer_base + + OMAP_DMTIMER_TIMER_WRITE_POST); + + while (dmt_read_4(sc, write_post_reg) & + OMAP_DMTIMER_REG_POSTED_MASK(reg)) { + if (--tries == 0) + panic("dmtimer %p failed to complete write", + sc); + DELAY(10); + } + } +} + +static uint32_t +dmt_read_4(struct omap_dmtimer_softc *sc, dmt_reg_t reg) +{ + + return bus_space_read_4(sc->sc_iot, sc->sc_ioh, reg); +} + +static void +dmt_write_4(struct omap_dmtimer_softc *sc, dmt_reg_t reg, uint32_t value) +{ + + bus_space_write_4(sc->sc_iot, sc->sc_ioh, reg, value); +} Index: sys/arch/arm/omap/omap_dmtimerreg.h =================================================================== RCS file: sys/arch/arm/omap/omap_dmtimerreg.h diff -N sys/arch/arm/omap/omap_dmtimerreg.h --- /dev/null 1 Jan 1970 00:00:00 -0000 +++ sys/arch/arm/omap/omap_dmtimerreg.h 11 Dec 2012 08:50:55 -0000 @@ -0,0 +1,167 @@ +/* $NetBSD$ */ + +/* + * TI OMAP Dual-mode timers: Registers + */ + +/*- + * Copyright (c) 2012 The NetBSD Foundation, Inc. + * All rights reserved. + * + * This code is derived from software contributed to The NetBSD Foundation + * by Taylor R. Campbell. + * + * 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. + */ + +/* + * References: TI AM335x TRM, TI OMAP35x TRM. + */ + +#ifndef _ARM_OMAP_OMAP_DMTIMERREG_H_ +#define _ARM_OMAP_OMAP_DMTIMERREG_H_ + +#include + +#define OMAP_DMTIMER_ID 0x00 /* TIDR */ +#define OMAP_DMTIMER_OCP_CFG 0x10 /* TOCP_CFG */ + +#define OMAP_DMTIMER_OCP_CFG_IDLEMODE_FORCE_IDLE 0 +#define OMAP_DMTIMER_OCP_CFG_IDLEMODE_NO_IDLE 1 +#define OMAP_DMTIMER_OCP_CFG_IDLEMODE_SMART_IDLE 2 +#define OMAP_DMTIMER_OCP_CFG_IDLEMODE_RESERVED 3 + +/* + * DM timer version 1 + */ + +#define OMAP_DMTIMER_V1_ID_REVISION_MASK __BITS(0, 7) +#define OMAP_DMTIMER_V1_ID_RESERVED_MASK __BITS(8, 31) + +#define OMAP_DMTIMER_V1_OCP_CFG_AUTOIDLE_MASK __BITS(0, 0) +#define OMAP_DMTIMER_V1_OCP_CFG_SOFTRESET_MASK __BITS(1, 1) +#define OMAP_DMTIMER_V1_OCP_CFG_WAKEUP_MASK __BITS(2, 2) +#define OMAP_DMTIMER_V1_OCP_CFG_IDLEMODE_MASK __BITS(3, 4) +#define OMAP_DMTIMER_V1_OCP_CFG_EMUFREE_MASK __BITS(5, 5) +#define OMAP_DMTIMER_V1_OCP_CFG_RESERVED0_MASK __BITS(6, 8) +#define OMAP_DMTIMER_V1_OCP_CFG_CLOCKACT_MASK __BITS(9, 8) +#define OMAP_DMTIMER_V1_OCP_CFG_CLOCKACT_OFF 0 +#define OMAP_DMTIMER_V1_OCP_CFG_CLOCKACT_FUN 1 +#define OMAP_DMTIMER_V1_OCP_CFG_CLOCKACT_L4 2 +#define OMAP_DMTIMER_V1_OCP_CFG_CLOCKACT_L4_FUN 3 + +#define OMAP_DMTIMER_INTR_MATCH __BIT(0) +#define OMAP_DMTIMER_INTR_OVERFLOW __BIT(1) +#define OMAP_DMTIMER_INTR_CAPTURE __BIT(2) +#define OMAP_DMTIMER_INTR_ALL 0x7 + +#define OMAP_DMTIMER_V1_STATUS 0x14 /* TISTAT */ +#define OMAP_DMTIMER_V1_STATUS_RESETDONE __BIT(0) +#define OMAP_DMTIMER_V1_INTR_STATUS 0x18 /* TISR */ +#define OMAP_DMTIMER_V1_INTR_ENABLE 0x1c /* TIER */ +#define OMAP_DMTIMER_V1_TIMER_REGS 0x20 + +/* + * DM timer version 2 + */ + +#define OMAP_DMTIMER_V2_ID_Y_MINOR_MASK __BITS(0, 5) +#define OMAP_DMTIMER_V2_ID_CUSTOM_MASK __BITS(6, 7) +#define OMAP_DMTIMER_V2_ID_X_MAJOR_MASK __BITS(8, 10) +#define OMAP_DMTIMER_V2_ID_R_RTL_MASK __BITS(11, 15) +#define OMAP_DMTIMER_V2_ID_FUNC_MASK __BITS(16, 27) +#define OMAP_DMTIMER_V2_ID_RESERVED_MASK __BITS(28, 29) +#define OMAP_DMTIMER_V2_ID_SCHEME_MASK __BITS(30, 31) + +#define OMAP_DMTIMER_V2_OCP_CFG_SOFTRESET_MASK __BITS(0, 0) +#define OMAP_DMTIMER_V2_OCP_CFG_EMUFREE_MASK __BITS(1, 1) +#define OMAP_DMTIMER_V2_OCP_CFG_IDLEMODE_MASK __BITS(2, 3) + +#define OMAP_DMTIMER_V2_INTR_STATUS_RAW 0x24 +#define OMAP_DMTIMER_V2_INTR_STATUS 0x28 +#define OMAP_DMTIMER_V2_INTR_ENABLE_SET 0x2c +#define OMAP_DMTIMER_V2_INTR_ENABLE_CLEAR 0x30 +#define OMAP_DMTIMER_V2_TIMER_REGS 0x34 + +#define OMAP_DMTIMER_REG_INDEX_MASK 0x00ff +#define OMAP_DMTIMER_REG_POSTED_BIT_MASK 0x0f00 +#define OMAP_DMTIMER_REG_POSTED_INDEX(reg) \ + __SHIFTOUT((reg), OMAP_DMTIMER_REG_INDEX_MASK) +#define OMAP_DMTIMER_REG_POSTED_BIT(reg) \ + __SHIFTOUT((reg), OMAP_DMTIMER_REG_POSTED_BIT_MASK) +#define OMAP_DMTIMER_REG_POSTED_MASK(reg) \ + __BIT(OMAP_DMTIMER_REG_POSTED_BIT(reg)) +#define OMAP_DMTIMER_REG_POSTED_P(reg) \ + (((reg) & 0x1000) == 0x1000) + +#define OMAP_DMTIMER_TIMER_INTR_WAKEUP 0x0000 /* TWER */ +#define OMAP_DMTIMER_TIMER_CTRL 0x1004 /* TCLR */ +#define OMAP_DMTIMER_TIMER_CTRL_START __BIT(0) +#define OMAP_DMTIMER_TIMER_CTRL_AUTORELOAD __BIT(1) +#define OMAP_DMTIMER_TIMER_CTRL_PRESCALE_MASK __BITS(2, 4) +#define OMAP_DMTIMER_TIMER_CTRL_PRESCALE_ENABLE __BIT(5) +#define OMAP_DMTIMER_TIMER_CTRL_COMPARE_ENABLE __BIT(6) +#define OMAP_DMTIMER_TIMER_CTRL_PWM_SIGN __BIT(7) +#define OMAP_DMTIMER_TIMER_CTRL_TCM_MASK __BITS(8, 9) +#define OMAP_DMTIMER_TIMER_CTRL_TCM_NONE 0 +#define OMAP_DMTIMER_TIMER_CTRL_TCM_LOW_HIGH 1 +#define OMAP_DMTIMER_TIMER_CTRL_TCM_HIGH_LOW 2 +#define OMAP_DMTIMER_TIMER_CTRL_TCM_BOTH 3 +#define OMAP_DMTIMER_TIMER_CTRL_TRG_MASK __BITS(10, 11) +#define OMAP_DMTIMER_TIMER_CTRL_TRG_NONE 0 +#define OMAP_DMTIMER_TIMER_CTRL_TRG_OVERFLOW 1 +#define OMAP_DMTIMER_TIMER_CTRL_TRG_OVERFLOW_MATCH 2 +#define OMAP_DMTIMER_TIMER_CTRL_TRG_RESERVED 3 +#define OMAP_DMTIMER_TIMER_CTRL_PWM_PT __BIT(12) +#define OMAP_DMTIMER_TIMER_CTRL_PWM_PULSE 0 +#define OMAP_DMTIMER_TIMER_CTRL_PWM_TOGGLE 1 +#define OMAP_DMTIMER_TIMER_CTRL_CAPTURE_MODE __BIT(13) +#define OMAP_DMTIMER_TIMER_CTRL_CAPTURE_MODE_FIRST 0 +#define OMAP_DMTIMER_TIMER_CTRL_CAPTURE_MODE_SECOND 1 +#define OMAP_DMTIMER_TIMER_CTRL_GPO_CFG __BIT(14) +#define OMAP_DMTIMER_TIMER_COUNTER 0x1108 /* TCRR */ +#define OMAP_DMTIMER_TIMER_LOAD 0x120c /* TLDR */ +#define OMAP_DMTIMER_TIMER_TRIGGER 0x1310 /* TTGR */ +#define OMAP_DMTIMER_TIMER_WRITE_POST 0x0014 /* TWPS */ +#define OMAP_DMTIMER_TIMER_WRITE_POST_CTRL __BIT(0) +#define OMAP_DMTIMER_TIMER_WRITE_POST_COUNTER __BIT(1) +#define OMAP_DMTIMER_TIMER_WRITE_POST_LOAD __BIT(2) +#define OMAP_DMTIMER_TIMER_WRITE_POST_TRIGGER __BIT(3) +#define OMAP_DMTIMER_TIMER_WRITE_POST_MATCH __BIT(4) +#define OMAP_DMTIMER_TIMER_WRITE_POST_POS_INCR __BIT(5) +#define OMAP_DMTIMER_TIMER_WRITE_POST_NEG_INCR __BIT(6) +#define OMAP_DMTIMER_TIMER_WRITE_POST_COUNTER_VALUE __BIT(7) +#define OMAP_DMTIMER_TIMER_WRITE_POST_INTR_MASK_SET __BIT(8) +#define OMAP_DMTIMER_TIMER_WRITE_POST_INTR_MASK_COUNT __BIT(9) +#define OMAP_DMTIMER_TIMER_MATCH 0x1418 /* TMAR */ +#define OMAP_DMTIMER_TIMER_CAPTURE1 0x001c /* TCAR1 */ +#define OMAP_DMTIMER_TIMER_SYNC_INT_CTRL 0x0020 /* TSICR */ +#define OMAP_DMTIMER_TIMER_SYNC_INT_CTRL_SOFTRESET __BIT(1) +#define OMAP_DMTIMER_TIMER_SYNC_INT_CTRL_POSTED __BIT(2) +#define OMAP_DMTIMER_TIMER_CAPTURE2 0x0024 /* TCAR2 */ +#define OMAP_DMTIMER_TICK_POS_INCR 0x1528 /* TPIR */ +#define OMAP_DMTIMER_TICK_NEG_INCR 0x162c /* TNIR */ +#define OMAP_DMTIMER_TICK_COUNTER_VALUE 0x1730 /* TCVR */ +#define OMAP_DMTIMER_TICK_INTR_MASK_SET 0x1834 /* TOCR */ +#define OMAP_DMTIMER_TICK_INTR_MASK_COUNT 0x1938 /* TOWR */ + +#endif /* _ARM_OMAP_OMAP_DMTIMERREG_H_ */ Index: sys/arch/arm/omap/omap_dmtimervar.h =================================================================== RCS file: sys/arch/arm/omap/omap_dmtimervar.h diff -N sys/arch/arm/omap/omap_dmtimervar.h --- /dev/null 1 Jan 1970 00:00:00 -0000 +++ sys/arch/arm/omap/omap_dmtimervar.h 11 Dec 2012 08:50:55 -0000 @@ -0,0 +1,62 @@ +/* $NetBSD$ */ + +/* + * TI OMAP Dual-mode timers: Driver state + */ + +/*- + * Copyright (c) 2012 The NetBSD Foundation, Inc. + * All rights reserved. + * + * This code is derived from software contributed to The NetBSD Foundation + * by Taylor R. Campbell. + * + * 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. + */ + +#ifndef _ARM_OMAP_OMAP_DMTIMERVAR_H_ +#define _ARM_OMAP_OMAP_DMTIMERVAR_H_ + +#include +#include +#include +#include + +struct omap_module; + +struct omap_dmtimer_softc { + device_t sc_dev; + const struct omap_module *sc_module; + unsigned int sc_version; + int sc_intr; + bus_space_tag_t sc_iot; + bus_space_handle_t sc_ioh; + + bool sc_posted; + bool sc_enabled; +}; + +void omap_dmtimer_attach_timecounter(struct omap_dmtimer_softc *); +void omap_dmtimer_attach_hardclock(struct omap_dmtimer_softc *); +void omap_dmtimer_attach_statclock(struct omap_dmtimer_softc *); + +#endif /* _ARM_OMAP_OMAP_DMTIMERVAR_H_ */