Home | History | Annotate | Line # | Download | only in ixp12x0
ixp12x0_clk.c revision 1.13
      1  1.13   martin /*	$NetBSD: ixp12x0_clk.c,v 1.13 2008/04/28 20:23:14 martin Exp $	*/
      2   1.1   ichiro 
      3   1.1   ichiro /*
      4   1.1   ichiro  * Copyright (c) 1997 Mark Brinicombe.
      5   1.1   ichiro  * Copyright (c) 1997 Causality Limited.
      6   1.1   ichiro  * All rights reserved.
      7   1.1   ichiro  *
      8   1.1   ichiro  * This code is derived from software contributed to The NetBSD Foundation
      9   1.1   ichiro  * by IWAMOTO Toshihiro and Ichiro FUKUHARA.
     10   1.1   ichiro  *
     11   1.1   ichiro  * Redistribution and use in source and binary forms, with or without
     12   1.1   ichiro  * modification, are permitted provided that the following conditions
     13   1.1   ichiro  * are met:
     14   1.1   ichiro  * 1. Redistributions of source code must retain the above copyright
     15   1.1   ichiro  *    notice, this list of conditions and the following disclaimer.
     16   1.1   ichiro  * 2. Redistributions in binary form must reproduce the above copyright
     17   1.1   ichiro  *    notice, this list of conditions and the following disclaimer in the
     18   1.1   ichiro  *    documentation and/or other materials provided with the distribution.
     19   1.1   ichiro  *
     20   1.1   ichiro  * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
     21   1.1   ichiro  * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
     22   1.1   ichiro  * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
     23   1.1   ichiro  * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
     24   1.1   ichiro  * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
     25   1.1   ichiro  * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
     26   1.1   ichiro  * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
     27   1.1   ichiro  * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
     28   1.1   ichiro  * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
     29   1.1   ichiro  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
     30   1.1   ichiro  * POSSIBILITY OF SUCH DAMAGE.
     31   1.1   ichiro  */
     32   1.7      igy 
     33   1.7      igy #include <sys/cdefs.h>
     34  1.13   martin __KERNEL_RCSID(0, "$NetBSD: ixp12x0_clk.c,v 1.13 2008/04/28 20:23:14 martin Exp $");
     35   1.1   ichiro 
     36   1.1   ichiro #include <sys/types.h>
     37   1.1   ichiro #include <sys/param.h>
     38  1.12    joerg #include <sys/atomic.h>
     39   1.1   ichiro #include <sys/systm.h>
     40   1.1   ichiro #include <sys/kernel.h>
     41   1.1   ichiro #include <sys/time.h>
     42  1.12    joerg #include <sys/timetc.h>
     43   1.1   ichiro #include <sys/device.h>
     44   1.1   ichiro 
     45   1.1   ichiro #include <machine/bus.h>
     46   1.1   ichiro #include <machine/intr.h>
     47   1.1   ichiro 
     48   1.1   ichiro #include <arm/cpufunc.h>
     49   1.1   ichiro 
     50   1.1   ichiro #include <arm/ixp12x0/ixpsipvar.h>
     51   1.1   ichiro 
     52   1.1   ichiro #include <arm/ixp12x0/ixp12x0_pcireg.h>
     53   1.1   ichiro #include <arm/ixp12x0/ixp12x0_clkreg.h>
     54   1.1   ichiro #include <arm/ixp12x0/ixp12x0var.h>
     55   1.1   ichiro 
     56   1.1   ichiro static int	ixpclk_match(struct device *, struct cfdata *, void *);
     57   1.1   ichiro static void	ixpclk_attach(struct device *, struct device *, void *);
     58   1.1   ichiro 
     59  1.12    joerg static u_int	ixpclk_get_timecount(struct timecounter *);
     60  1.12    joerg 
     61   1.1   ichiro int		gettick(void);
     62   1.1   ichiro void		rtcinit(void);
     63   1.1   ichiro 
     64   1.1   ichiro /* callback functions for intr_functions */
     65   1.1   ichiro static int      ixpclk_intr(void* arg);
     66   1.1   ichiro 
     67   1.1   ichiro struct ixpclk_softc {
     68   1.1   ichiro 	struct device		sc_dev;
     69   1.1   ichiro 	bus_addr_t		sc_baseaddr;
     70   1.1   ichiro 	bus_space_tag_t		sc_iot;
     71   1.1   ichiro 	bus_space_handle_t	sc_ioh;
     72   1.6   ichiro 	bus_space_handle_t	sc_pll_ioh;
     73   1.1   ichiro 
     74   1.1   ichiro 	u_int32_t		sc_clock_count;
     75   1.1   ichiro 	u_int32_t		sc_count_per_usec;
     76   1.1   ichiro 	u_int32_t		sc_coreclock_freq;
     77   1.1   ichiro };
     78   1.1   ichiro 
     79   1.1   ichiro #define XTAL_FREQ		3686400		/* 3.6864MHz */
     80   1.1   ichiro #define XTAL_FREQ3686400
     81   1.1   ichiro #undef XTAL_FREQ3787800
     82   1.1   ichiro #undef XTAL_FREQ3579500
     83   1.1   ichiro #define	MAX_CCF			22
     84   1.1   ichiro 
     85   1.1   ichiro #if defined(XTAL_FREQ3686400)
     86   1.1   ichiro static u_int32_t ccf_to_coreclock[MAX_CCF + 1] = {
     87   1.1   ichiro 	29491000,
     88   1.1   ichiro 	36865000,
     89   1.1   ichiro 	44237000,
     90   1.1   ichiro 	51610000,
     91   1.1   ichiro 	58982000,
     92   1.1   ichiro 	66355000,
     93   1.1   ichiro 	73728000,
     94   1.1   ichiro 	81101000,
     95   1.1   ichiro 	88474000,
     96   1.1   ichiro 	95846000,
     97   1.1   ichiro 	103219000,
     98   1.1   ichiro 	110592000,
     99   1.1   ichiro 	132710000,
    100   1.1   ichiro 	147456000,
    101   1.1   ichiro 	154829000,
    102   1.1   ichiro 	162202000,
    103   1.1   ichiro 	165890000,
    104   1.1   ichiro 	176947000,
    105   1.1   ichiro 	191693000,
    106   1.1   ichiro 	199066000,
    107   1.1   ichiro 	206438000,
    108   1.1   ichiro 	221184000,
    109   1.1   ichiro 	232243000,
    110   1.1   ichiro };
    111   1.1   ichiro #elif defined(XTAL_FREQ3787800)
    112   1.1   ichiro #elif defined(XTAL_FREQ3579500)
    113   1.1   ichiro #else
    114   1.1   ichiro #error
    115   1.1   ichiro #endif
    116   1.1   ichiro 
    117   1.1   ichiro static struct ixpclk_softc *ixpclk_sc = NULL;
    118   1.1   ichiro 
    119  1.12    joerg static struct timecounter ixpclk_timecounter = {
    120  1.12    joerg 	ixpclk_get_timecount,	/* get_timecount */
    121  1.12    joerg 	0,			/* no poll_pps */
    122  1.12    joerg 	0xffffffff,		/* counter_mask */
    123  1.12    joerg 	0,			/* frequency */
    124  1.12    joerg 	"ixpclk",		/* name */
    125  1.12    joerg 	100,			/* quality */
    126  1.12    joerg 	NULL,			/* prev */
    127  1.12    joerg 	NULL,			/* next */
    128  1.12    joerg };
    129  1.12    joerg 
    130  1.12    joerg static volatile uint32_t ixpclk_base;
    131  1.12    joerg 
    132   1.1   ichiro #define TIMER_FREQUENCY         3686400         /* 3.6864MHz */
    133   1.1   ichiro #define TICKS_PER_MICROSECOND   (TIMER_FREQUENCY/1000000)
    134   1.1   ichiro 
    135   1.5  thorpej CFATTACH_DECL(ixpclk, sizeof(struct ixpclk_softc),
    136   1.5  thorpej     ixpclk_match, ixpclk_attach, NULL, NULL);
    137   1.1   ichiro 
    138   1.1   ichiro #define GET_TIMER_VALUE(sc)	(bus_space_read_4((sc)->sc_iot,		\
    139   1.1   ichiro 						  (sc)->sc_ioh,		\
    140   1.1   ichiro 						  IXPCLK_VALUE)		\
    141   1.1   ichiro 				 & IXPCL_CTV)
    142   1.1   ichiro 
    143   1.1   ichiro static int
    144   1.8      igy ixpclk_match(struct device *parent, struct cfdata *match, void *aux)
    145   1.1   ichiro {
    146   1.8      igy 
    147   1.6   ichiro 	return 2;
    148   1.1   ichiro }
    149   1.1   ichiro 
    150   1.1   ichiro static void
    151   1.8      igy ixpclk_attach(struct device *parent, struct device *self, void *aux)
    152   1.1   ichiro {
    153   1.8      igy 	struct ixpclk_softc		*sc;
    154   1.8      igy 	struct ixpsip_attach_args	*sa;
    155   1.6   ichiro 	u_int32_t			ccf;
    156  1.12    joerg 	bool first_run = ixpclk_sc == NULL;
    157   1.1   ichiro 
    158   1.1   ichiro 	printf("\n");
    159   1.1   ichiro 
    160   1.8      igy 	sc = (struct ixpclk_softc*) self;
    161   1.8      igy 	sa = aux;
    162   1.1   ichiro 	sc->sc_iot = sa->sa_iot;
    163   1.1   ichiro 	sc->sc_baseaddr = sa->sa_addr;
    164   1.1   ichiro 
    165   1.1   ichiro 	/* using first timer for system ticks */
    166   1.1   ichiro 	if (ixpclk_sc == NULL)
    167   1.1   ichiro 		ixpclk_sc = sc;
    168   1.1   ichiro 
    169   1.1   ichiro 	if (bus_space_map(sa->sa_iot, sa->sa_addr, sa->sa_size, 0,
    170   1.1   ichiro 			  &sc->sc_ioh))
    171   1.3   provos 		panic("%s: Cannot map registers", self->dv_xname);
    172   1.6   ichiro 	if (bus_space_map(sa->sa_iot, sa->sa_addr + IXPCLK_PLL_CFG_OFFSET,
    173   1.6   ichiro 			  IXPCLK_PLL_CFG_SIZE, 0, &sc->sc_pll_ioh))
    174   1.6   ichiro 		panic("%s: Cannot map registers", self->dv_xname);
    175   1.1   ichiro 
    176   1.1   ichiro 	/* disable all channel and clear interrupt status */
    177   1.1   ichiro 	bus_space_write_4(sc->sc_iot, sc->sc_ioh, IXPCLK_CONTROL,
    178   1.1   ichiro 			  IXPCL_DISABLE | IXPCL_PERIODIC | IXPCL_STP_CORE);
    179   1.1   ichiro 	bus_space_write_4(sc->sc_iot, sc->sc_ioh, IXPCLK_CLEAR, 0);
    180   1.6   ichiro 
    181   1.6   ichiro 
    182   1.6   ichiro 	ccf = bus_space_read_4(sc->sc_iot, sc->sc_pll_ioh, 0)
    183   1.6   ichiro 		& IXP12X0_PLL_CFG_CCF;
    184   1.6   ichiro 	sc->sc_coreclock_freq = ccf_to_coreclock[ccf];
    185   1.6   ichiro 
    186   1.6   ichiro 	sc->sc_clock_count = sc->sc_coreclock_freq / hz;
    187   1.6   ichiro 	sc->sc_count_per_usec = sc->sc_coreclock_freq / 1000000;
    188   1.6   ichiro 
    189   1.6   ichiro 	bus_space_write_4(sc->sc_iot, sc->sc_ioh, IXPCLK_CLEAR, IXPT_CLEAR);
    190   1.6   ichiro 	bus_space_write_4(sc->sc_iot, sc->sc_ioh, IXPCLK_LOAD,
    191   1.6   ichiro 			  sc->sc_clock_count);
    192   1.6   ichiro 	bus_space_write_4(sc->sc_iot, sc->sc_ioh, IXPCLK_CONTROL,
    193   1.6   ichiro 			  IXPCL_ENABLE | IXPCL_PERIODIC | IXPCL_STP_CORE);
    194   1.6   ichiro 
    195  1.12    joerg 	if (first_run) {
    196  1.12    joerg 		ixpclk_timecounter.tc_frequency = sc->sc_coreclock_freq;
    197  1.12    joerg 		tc_init(&ixpclk_timecounter);
    198  1.12    joerg 	}
    199  1.12    joerg 
    200   1.6   ichiro 	printf("%s: IXP12x0 Interval Timer (core clock %d.%03dMHz)\n",
    201   1.6   ichiro 	       sc->sc_dev.dv_xname,
    202   1.6   ichiro 	       sc->sc_coreclock_freq / 1000000,
    203   1.6   ichiro 	       (sc->sc_coreclock_freq % 1000000) / 1000);
    204   1.1   ichiro }
    205   1.1   ichiro 
    206   1.1   ichiro /*
    207   1.1   ichiro  * ixpclk_intr:
    208   1.1   ichiro  *
    209   1.1   ichiro  *	Handle the hardclock interrupt.
    210   1.1   ichiro  */
    211   1.1   ichiro static int
    212   1.1   ichiro ixpclk_intr(void *arg)
    213   1.1   ichiro {
    214   1.8      igy 
    215   1.1   ichiro 	bus_space_write_4(ixpclk_sc->sc_iot, ixpclk_sc->sc_ioh,
    216   1.1   ichiro 			  IXPCLK_CLEAR, 1);
    217   1.1   ichiro 
    218  1.12    joerg 	atomic_add_32(&ixpclk_base, ixpclk_sc->sc_coreclock_freq);
    219  1.12    joerg 
    220   1.1   ichiro 	hardclock((struct clockframe*) arg);
    221   1.1   ichiro 	return (1);
    222   1.1   ichiro }
    223   1.1   ichiro 
    224   1.1   ichiro /*
    225   1.1   ichiro  * setstatclockrate:
    226   1.1   ichiro  *
    227   1.1   ichiro  *	Set the rate of the statistics clock.
    228   1.1   ichiro  *
    229   1.1   ichiro  *	We assume that hz is either stathz or profhz, and that neither
    230   1.1   ichiro  *	will change after being set by cpu_initclocks().  We could
    231   1.1   ichiro  *	recalculate the intervals here, but that would be a pain.
    232   1.1   ichiro  */
    233   1.1   ichiro void
    234   1.9       he setstatclockrate(int newhz)
    235   1.1   ichiro {
    236   1.8      igy 
    237   1.1   ichiro 	/* use hardclock */
    238   1.1   ichiro 
    239   1.1   ichiro 	/* XXX should I use TIMER2? */
    240   1.1   ichiro }
    241   1.1   ichiro 
    242   1.1   ichiro /*
    243   1.1   ichiro  * cpu_initclocks:
    244   1.1   ichiro  *
    245   1.1   ichiro  *	Initialize the clock and get them going.
    246   1.1   ichiro  */
    247   1.1   ichiro void
    248   1.8      igy cpu_initclocks(void)
    249   1.1   ichiro {
    250   1.8      igy 	struct ixpclk_softc*	sc;
    251   1.1   ichiro 
    252   1.8      igy 	sc = ixpclk_sc;
    253   1.1   ichiro 	stathz = profhz = 0;
    254   1.1   ichiro 
    255   1.1   ichiro 	printf("clock: hz = %d stathz = %d\n", hz, stathz);
    256   1.1   ichiro 
    257   1.6   ichiro 	bus_space_write_4(sc->sc_iot, sc->sc_ioh, IXPCLK_CONTROL,
    258   1.6   ichiro 			  IXPCL_DISABLE);
    259   1.1   ichiro 	bus_space_write_4(sc->sc_iot, sc->sc_ioh, IXPCLK_CLEAR, IXPT_CLEAR);
    260   1.1   ichiro 
    261   1.1   ichiro 	ixp12x0_intr_establish(IXPPCI_INTR_T1, IPL_CLOCK, ixpclk_intr, NULL);
    262   1.1   ichiro 
    263   1.1   ichiro 	bus_space_write_4(sc->sc_iot, sc->sc_ioh, IXPCLK_LOAD,
    264   1.1   ichiro 			  sc->sc_clock_count);
    265   1.1   ichiro 	bus_space_write_4(sc->sc_iot, sc->sc_ioh, IXPCLK_CONTROL,
    266   1.1   ichiro 			  IXPCL_ENABLE | IXPCL_PERIODIC
    267   1.1   ichiro 			  | IXPCL_STP_CORE);
    268   1.1   ichiro }
    269   1.1   ichiro 
    270   1.1   ichiro int
    271   1.8      igy gettick(void)
    272   1.1   ichiro {
    273   1.8      igy 	int	counter;
    274   1.8      igy 	u_int	savedints;
    275   1.8      igy 
    276   1.1   ichiro 	savedints = disable_interrupts(I32_bit);
    277   1.1   ichiro 	counter = GET_TIMER_VALUE(ixpclk_sc);
    278   1.1   ichiro 	restore_interrupts(savedints);
    279   1.1   ichiro 	return counter;
    280   1.1   ichiro }
    281   1.1   ichiro 
    282  1.12    joerg static u_int
    283  1.12    joerg ixpclk_get_timecount(struct timecounter *tc)
    284   1.1   ichiro {
    285  1.12    joerg 	u_int	savedints, base, counter;
    286   1.1   ichiro 
    287  1.12    joerg 	savedints = disable_interrupts(I32_bit);
    288  1.12    joerg 	do {
    289  1.12    joerg 		base = ixpclk_base;
    290  1.12    joerg 		counter = GET_TIMER_VALUE(ixpclk_sc);
    291  1.12    joerg 	} while (base != ixpclk_base);
    292  1.12    joerg 	restore_interrupts(savedints);
    293   1.1   ichiro 
    294  1.12    joerg 	return base - counter;
    295   1.1   ichiro }
    296   1.1   ichiro 
    297   1.1   ichiro /*
    298   1.1   ichiro  * delay:
    299   1.1   ichiro  *
    300   1.1   ichiro  *	Delay for at least N microseconds.
    301   1.1   ichiro  */
    302   1.1   ichiro void
    303   1.6   ichiro delay(unsigned int usecs)
    304   1.1   ichiro {
    305   1.6   ichiro 	u_int32_t	count;
    306   1.9       he 	u_int32_t	ticks;
    307   1.6   ichiro 	u_int32_t	otick;
    308   1.6   ichiro 	u_int32_t	delta;
    309   1.6   ichiro 	int		j;
    310   1.8      igy 	int		csec;
    311   1.8      igy 	int		usec;
    312   1.1   ichiro 
    313   1.1   ichiro 	if (ixpclk_sc == NULL) {
    314   1.1   ichiro #ifdef DEBUG
    315   1.6   ichiro 		printf("delay: called befor start ixpclk\n");
    316   1.1   ichiro #endif
    317   1.1   ichiro 
    318   1.6   ichiro 		csec = usecs / 10000;
    319   1.6   ichiro 		usec = usecs % 10000;
    320   1.6   ichiro 
    321   1.1   ichiro 		usecs = (TIMER_FREQUENCY / 100) * csec
    322   1.1   ichiro 			+ (TIMER_FREQUENCY / 100) * usec / 10000;
    323   1.1   ichiro 		/* clock isn't initialized yet */
    324   1.1   ichiro 		for(; usecs > 0; usecs--)
    325   1.1   ichiro 			for(j = 100; j > 0; j--)
    326   1.1   ichiro 				;
    327   1.1   ichiro 		return;
    328   1.1   ichiro 	}
    329   1.1   ichiro 
    330   1.6   ichiro 	count = ixpclk_sc->sc_count_per_usec * usecs;
    331   1.1   ichiro 
    332   1.1   ichiro 	otick = gettick();
    333   1.1   ichiro 
    334   1.6   ichiro 	for (;;) {
    335   1.1   ichiro 		for(j = 100; j > 0; j--)
    336   1.1   ichiro 			;
    337   1.6   ichiro 
    338   1.9       he 		ticks = gettick();
    339   1.9       he 		delta = otick < ticks
    340   1.9       he 			? ixpclk_sc->sc_clock_count + otick - ticks
    341   1.9       he 			: otick - ticks;
    342   1.1   ichiro 
    343   1.6   ichiro 		if (delta > count)
    344   1.1   ichiro 			break;
    345   1.6   ichiro 
    346   1.6   ichiro 		count -= delta;
    347   1.9       he 		otick = ticks;
    348   1.1   ichiro 	}
    349   1.1   ichiro }
    350