Subject: kern/34683: OMAP patch 4/5: RTC driver
To: None <kern-bug-people@netbsd.org, gnats-admin@netbsd.org,>
From: Bucky Katz <bucky@picovex.com>
List: netbsd-bugs
Date: 10/01/2006 03:25:01
>Number: 34683
>Category: kern
>Synopsis: OMAP patch 4/5: RTC driver
>Confidential: no
>Severity: serious
>Priority: medium
>Responsible: kern-bug-people
>State: open
>Class: sw-bug
>Submitter-Id: net
>Arrival-Date: Sun Oct 01 03:25:00 +0000 2006
>Originator: Bucky Katz
>Release: NetBSD 4.99.3
>Organization:
Picovex
>Environment:
System: NetBSD katz.picovex.com 4.99.3 NetBSD 4.99.3 (BUCKY) #5: Fri Sep 29 17:38:54 PDT 2006 root@katz.picovex.com:/usr/obj/sys/arch/evbarm/compile/BUCKY evbarm
Architecture: evbarm
Machine: OSK5912
>Description:
The attached patch adds support for the OMAP Real Time Clock. The patch
depends upon the patch "Generic TODR for ARM ports" sent 09/19/2006 by
Garrett D'Amore.
>How-To-Repeat:
Attempt to build OSK5912 kernel
>Fix:
--=-=-=
Content-Type: text/x-patch
Content-Disposition: inline; filename=omap_rtc.patch
Content-Description: OMAP patch 4/5: RTC driver
Index: netbsd_quilt/src/sys/arch/arm/omap/files.omap
===================================================================
--- netbsd_quilt.orig/src/sys/arch/arm/omap/files.omap
+++ netbsd_quilt/src/sys/arch/arm/omap/files.omap
@@ -124,3 +124,8 @@ defparam opt_omap.h OMAP_MPU_TIMER_CL
device omapgpio
attach omapgpio at tipb
file arch/arm/omap/omap_gpio.c omapgpio needs-count
+
+# RTC
+device omaprtc
+attach omaprtc at tipb
+file arch/arm/omap/omap_rtc.c omaprtc
Index: netbsd_quilt/src/sys/arch/arm/omap/omap_rtc.c
===================================================================
--- /dev/null
+++ netbsd_quilt/src/sys/arch/arm/omap/omap_rtc.c
@@ -0,0 +1,248 @@
+/* $NetBSD: $ */
+
+/*
+ * OMAP RTC driver, based on i80321_timer.c.
+ *
+ * Copyright (c) 2001, 2002 Wasabi Systems, Inc.
+ * All rights reserved.
+ *
+ * Written by Jason R. Thorpe for Wasabi Systems, Inc.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed for the NetBSD Project by
+ * Wasabi Systems, Inc.
+ * 4. The name of Wasabi Systems, Inc. may not be used to endorse
+ * or promote products derived from this software without specific prior
+ * written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY WASABI SYSTEMS, INC. ``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 WASABI SYSTEMS, INC
+ * 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>
+__KERNEL_RCSID(0, "$NetBSD: $");
+
+#include <sys/types.h>
+#include <sys/param.h>
+#include <sys/systm.h>
+#include <sys/kernel.h>
+#include <sys/time.h>
+#include <sys/device.h>
+#include <dev/clock_subr.h>
+
+#include <machine/bus.h>
+#include <machine/intr.h>
+
+#include <arm/omap/omap_reg.h>
+#include <arm/omap/omap_tipb.h>
+
+/* RTC year values relative to this year */
+
+#define BASEYEAR 2000
+
+/* Register offsets and bit fields. */
+
+#define SECONDS_REG 0x00
+#define MINUTES_REG 0x04
+#define HOURS_REG 0x08
+#define DAYS_REG 0x0c
+#define MONTHS_REG 0x10
+#define YEARS_REG 0x14
+#define WEEKS_REG 0x18
+#define ALARM_SECONDS_REG 0x20
+#define ALARM_MINUTES_REG 0x24
+#define ALARM_HOURS_REG 0x28
+#define ALARM_DAYS_REG 0x2c
+#define ALARM_MONTHS_REG 0x30
+#define ALARM_YEARS_REG 0x34
+
+#define RTC_CTRL_REG 0x40
+#define STOP_RTC 0
+
+#define RTC_STATUS_REG 0x44
+#define ALARM 6
+#define BUSY 0
+
+#define RTC_INTERRUPTS_REG 0x48
+#define IT_ALARM 3
+
+static int omaprtc_match(struct device *, struct cfdata *, void *);
+static void omaprtc_attach(struct device *, struct device *, void *);
+
+struct omaprtc_softc {
+ struct device sc_dev;
+ bus_space_tag_t sc_iot;
+ bus_space_handle_t sc_ioh;
+ int sc_intr;
+ void *sc_irqcookie;
+ struct todr_chip_handle sc_todr;
+};
+
+CFATTACH_DECL(omaprtc, sizeof(struct omaprtc_softc),
+ omaprtc_match, omaprtc_attach, NULL, NULL);
+
+static int omaprtc_gettime(todr_chip_handle_t, struct clock_ymdhms *);
+static int omaprtc_settime(todr_chip_handle_t, struct clock_ymdhms *);
+
+#define rtc_is_busy() (bus_space_read_1(sc->sc_iot, sc->sc_ioh, \
+ RTC_STATUS_REG) & 1<<BUSY)
+
+static int
+omaprtc_gettime(todr_chip_handle_t tch, struct clock_ymdhms *dt)
+{
+ struct omaprtc_softc *sc = tch->cookie;
+ int s;
+
+ /* Wait for RTC_STATUS_REG:BUSY to go low to
+ * guarantee our read is correct. BUSY will
+ * only be high for one 32kHz period (30.5us)
+ * each second, so we'll usually pass right
+ * through.
+ *
+ * Watch RTC_CTRL_REG:STOP_RTC as well so
+ * we don't spin forever if someone disables the RTC.
+ *
+ * Turn interrupts off, because we are only allowed
+ * to read/write the registers for 1/2 of a 32kHz
+ * clock period (= 15us) after detecting that BUSY
+ * is low.
+ */
+
+ s = disable_interrupts(I32_bit);
+
+ while (rtc_is_busy()) {
+ ;
+ }
+
+ dt->dt_year =
+ FROMBCD(bus_space_read_1(sc->sc_iot,
+ sc->sc_ioh,
+ YEARS_REG)) + BASEYEAR;
+ dt->dt_mon =
+ FROMBCD(bus_space_read_1(sc->sc_iot,
+ sc->sc_ioh,
+ MONTHS_REG));
+ dt->dt_wday =
+ FROMBCD(bus_space_read_1(sc->sc_iot,
+ sc->sc_ioh,
+ WEEKS_REG) & 0x0f);
+ dt->dt_day =
+ FROMBCD(bus_space_read_1(sc->sc_iot,
+ sc->sc_ioh,
+ DAYS_REG));
+ dt->dt_sec =
+ FROMBCD(bus_space_read_1(sc->sc_iot,
+ sc->sc_ioh,
+ SECONDS_REG));
+ dt->dt_hour =
+ FROMBCD(bus_space_read_1(sc->sc_iot,
+ sc->sc_ioh,
+ HOURS_REG));
+ dt->dt_min =
+ FROMBCD(bus_space_read_1(sc->sc_iot,
+ sc->sc_ioh,
+ MINUTES_REG));
+ restore_interrupts(s);
+ return 0;
+}
+
+static int
+omaprtc_settime(todr_chip_handle_t tch, struct clock_ymdhms *dt)
+{
+ struct omaprtc_softc *sc = tch->cookie;
+ int s;
+
+ s = disable_interrupts(I32_bit);
+
+ while (rtc_is_busy()) {
+ ;
+ }
+
+ /* It's ok to write these without stopping the
+ * RTC, because the BUSY mechanism lets us guarantee
+ * that we're not in the middle of, e.g., rolling
+ * seconds into minutes.
+ */
+
+ bus_space_write_1(sc->sc_iot, sc->sc_ioh,
+ YEARS_REG, TOBCD(dt->dt_year - BASEYEAR));
+ bus_space_write_1(sc->sc_iot, sc->sc_ioh,
+ MONTHS_REG, TOBCD(dt->dt_mon));
+ bus_space_write_1(sc->sc_iot, sc->sc_ioh,
+ WEEKS_REG, TOBCD(dt->dt_wday & 0x0f));
+ bus_space_write_1(sc->sc_iot, sc->sc_ioh,
+ DAYS_REG, TOBCD(dt->dt_day));
+ bus_space_write_1(sc->sc_iot, sc->sc_ioh,
+ SECONDS_REG, TOBCD(dt->dt_sec));
+ bus_space_write_1(sc->sc_iot, sc->sc_ioh,
+ HOURS_REG, TOBCD(dt->dt_hour));
+ bus_space_write_1(sc->sc_iot, sc->sc_ioh,
+ MINUTES_REG, TOBCD(dt->dt_min));
+ restore_interrupts(s);
+ return 0;
+}
+
+static int
+omaprtc_match(struct device *parent, struct cfdata *match, void *aux)
+{
+ struct tipb_attach_args *tipb = aux;
+
+ if (tipb->tipb_addr == -1)
+ panic("omaprtc must have addr specified in config.");
+
+ if (tipb->tipb_size == 0)
+ tipb->tipb_size = 2048; /* Per the OMAP TRM. */
+
+ /* We implicitly trust the config file. */
+ return (1);
+}
+
+void
+omaprtc_attach(struct device *parent, struct device *self, void *aux)
+{
+ struct omaprtc_softc *sc = (struct omaprtc_softc*)self;
+ struct tipb_attach_args *tipb = aux;
+
+ sc->sc_iot = tipb->tipb_iot;
+ sc->sc_intr = tipb->tipb_intr;
+
+ if (bus_space_map(tipb->tipb_iot, tipb->tipb_addr, tipb->tipb_size, 0,
+ &sc->sc_ioh))
+ panic("%s: Cannot map registers", self->dv_xname);
+
+ aprint_normal(": OMAP RTC\n");
+ aprint_naive("\n");
+
+ /*
+ * Start RTC (STOP_RTC=1 starts it, go figure), 24 hour mode,
+ * no autocompensation, no rounding, 32KHz clock enabled,
+ * cannot use split power, no test mode.
+ */
+
+ bus_space_write_1(sc->sc_iot, sc->sc_ioh, RTC_CTRL_REG,
+ 1 << STOP_RTC);
+
+ sc->sc_todr.cookie = sc;
+ sc->sc_todr.todr_gettime_ymdhms = omaprtc_gettime;
+ sc->sc_todr.todr_settime_ymdhms = omaprtc_settime;
+ todr_attach(&sc->sc_todr);
+}
+
--=-=-=--
>Unformatted:
--=-=-=