1 /* $NetBSD: sbtimer.c,v 1.14 2009/08/12 12:56:29 simonb Exp $ */
5 * Broadcom Corporation. All rights reserved.
7 * This software is furnished under license and may be used and copied only
8 * in accordance with the following terms and conditions. Subject to these
9 * conditions, you may download, copy, install, use, modify and distribute
10 * modified or unmodified copies of this software in source and/or binary
11 * form. No title or ownership is transferred hereby.
13 * 1) Any source code used, modified or distributed must reproduce and
14 * retain this copyright notice and list of conditions as they appear in
17 * 2) No right is granted to use any trade name, trademark, or logo of
18 * Broadcom Corporation. The "Broadcom Corporation" name may not be
19 * used to endorse or promote products derived from this software
20 * without the prior written permission of Broadcom Corporation.
22 * 3) THIS SOFTWARE IS PROVIDED "AS-IS" AND ANY EXPRESS OR IMPLIED
23 * WARRANTIES, INCLUDING BUT NOT LIMITED TO, ANY IMPLIED WARRANTIES OF
24 * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, OR
25 * NON-INFRINGEMENT ARE DISCLAIMED. IN NO EVENT SHALL BROADCOM BE LIABLE
26 * FOR ANY DAMAGES WHATSOEVER, AND IN PARTICULAR, BROADCOM SHALL NOT BE
27 * LIABLE FOR DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
28 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
29 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
30 * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
31 * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
32 * OR OTHERWISE), EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
35 #include <sys/cdefs.h>
36 __KERNEL_RCSID(0, "$NetBSD: sbtimer.c,v 1.14 2009/08/12 12:56:29 simonb Exp $");
38 #include <sys/param.h>
39 #include <sys/device.h>
40 #include <sys/systm.h>
41 #include <sys/kernel.h>
43 #include <mips/locore.h>
45 #include <mips/sibyte/include/sb1250_regs.h>
46 #include <mips/sibyte/include/sb1250_scd.h>
47 #include <mips/sibyte/dev/sbscdvar.h>
49 struct sbtimer_softc
{
53 void *sc_addr_icnt
, *sc_addr_cnt
, *sc_addr_cfg
;
55 #define SBTIMER_CLOCK 1
56 #define SBTIMER_STATCLOCK 2
58 #define READ_REG(rp) (mips3_ld((volatile uint64_t *)(rp)))
59 #define WRITE_REG(rp, val) (mips3_sd((volatile uint64_t *)(rp), (val)))
61 static int sbtimer_match(struct device
*, struct cfdata
*, void *);
62 static void sbtimer_attach(struct device
*, struct device
*, void *);
64 CFATTACH_DECL(sbtimer
, sizeof(struct sbtimer_softc
),
65 sbtimer_match
, sbtimer_attach
, NULL
, NULL
);
67 static void sbtimer_clockintr(void *arg
, uint32_t status
, vaddr_t pc
);
68 static void sbtimer_statclockintr(void *arg
, uint32_t status
, vaddr_t pc
);
69 static void sbtimer_miscintr(void *arg
, uint32_t status
, vaddr_t pc
);
71 static void sbtimer_clock_init(void *arg
);
74 sbtimer_match(struct device
*parent
, struct cfdata
*match
, void *aux
)
76 struct sbscd_attach_args
*sap
= aux
;
78 if (sap
->sa_locs
.sa_type
!= SBSCD_DEVTYPE_TIMER
)
85 sbtimer_attach(struct device
*parent
, struct device
*self
, void *aux
)
87 struct sbscd_attach_args
*sa
= aux
;
88 struct sbtimer_softc
*sc
= (struct sbtimer_softc
*)self
;
89 void (*fun
)(void *, uint32_t, vaddr_t
);
91 const char *comment
= "";
93 sc
->sc_flags
= device_cfdata(&sc
->sc_dev
)->cf_flags
;
94 sc
->sc_addr_icnt
= (uint64_t *)MIPS_PHYS_TO_KSEG1(sa
->sa_locs
.sa_addr
+
96 sc
->sc_addr_cnt
= (uint64_t *)MIPS_PHYS_TO_KSEG1(sa
->sa_locs
.sa_addr
+
98 sc
->sc_addr_cfg
= (uint64_t *)MIPS_PHYS_TO_KSEG1(sa
->sa_locs
.sa_addr
+
102 if ((sc
->sc_flags
& SBTIMER_CLOCK
) != 0) {
104 fun
= sbtimer_clockintr
;
106 if (system_set_clockfns(sc
, sbtimer_clock_init
)) {
107 /* not really the clock */
108 sc
->sc_flags
&= ~SBTIMER_CLOCK
;
109 comment
= " (not system timer)";
112 printf("system timer");
113 } else if ((sc
->sc_flags
& SBTIMER_STATCLOCK
) != 0) {
115 fun
= sbtimer_statclockintr
;
117 /* XXX make sure it's the statclock */
119 /* not really the statclock */
120 sc
->sc_flags
&= ~SBTIMER_STATCLOCK
;
121 comment
= " (not system statistics timer)";
124 printf("system statistics timer");
127 ipl
= IPL_BIO
; /* XXX -- pretty low */
128 fun
= sbtimer_miscintr
;
129 printf("general-purpose timer%s", comment
);
133 /* clear intr & disable timer. */
134 WRITE_REG(sc
->sc_addr_cfg
, 0x00); /* XXX */
136 sc
->sc_intrhand
= cpu_intr_establish(sa
->sa_locs
.sa_intr
[0], ipl
,
141 sbtimer_clock_init(void *arg
)
143 struct sbtimer_softc
*sc
= arg
;
145 printf("%s: ", sc
->sc_dev
.dv_xname
);
146 if ((1000000 % hz
) == 0)
147 printf("%dHz system timer\n", hz
);
149 printf("cannot get %dHz clock; using 1000Hz\n", hz
);
154 WRITE_REG(sc
->sc_addr_cfg
, 0x00); /* XXX */
155 if (G_SYS_PLL_DIV(READ_REG(MIPS_PHYS_TO_KSEG1(A_SCD_SYSTEM_CFG
))) == 0) {
156 printf("%s: PLL_DIV == 0; speeding up clock ticks for simulator\n",
157 sc
->sc_dev
.dv_xname
);
158 WRITE_REG(sc
->sc_addr_icnt
, (tick
/100) - 1); /* XXX */
160 WRITE_REG(sc
->sc_addr_icnt
, tick
- 1); /* XXX */
162 WRITE_REG(sc
->sc_addr_cfg
, 0x03); /* XXX */
166 sbtimer_clockintr(void *arg
, uint32_t status
, vaddr_t pc
)
168 struct sbtimer_softc
*sc
= arg
;
169 struct clockframe cf
;
171 /* clear interrupt, but leave timer enabled and in repeating mode */
172 WRITE_REG(sc
->sc_addr_cfg
, 0x03); /* XXX */
180 * We never want a CPU core clock interrupt, so adjust the CP0
181 * compare register to just before the CP0 clock register's value
184 mips3_cp0_compare_write(mips3_cp0_count_read() - 1);
188 sbtimer_statclockintr(void *arg
, uint32_t status
, vaddr_t pc
)
190 struct sbtimer_softc
*sc
= arg
;
191 struct clockframe cf
;
193 /* clear intr & disable timer, reset initial count, re-enable timer */
194 WRITE_REG(sc
->sc_addr_cfg
, 0x00); /* XXX */
204 sbtimer_miscintr(void *arg
, uint32_t status
, vaddr_t pc
)
206 struct sbtimer_softc
*sc
= arg
;
209 WRITE_REG(sc
->sc_addr_cfg
, 0x00); /* XXX */