Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 9b2e43ae authored by David S. Miller's avatar David S. Miller
Browse files

sparc32: Use PROM device probing for sun4m timer registers.

parent 3c503701
Loading
Loading
Loading
Loading
+0 −43
Original line number Diff line number Diff line
@@ -35,49 +35,6 @@ struct sun4c_timer_info {

#define SUN_TIMER_PHYSADDR   0xf3000000

/* A sun4m has two blocks of registers which are probably of the same
 * structure. LSI Logic's L64851 is told to _decrement_ from the limit
 * value. Aurora behaves similarly but its limit value is compacted in
 * other fashion (it's wider). Documented fields are defined here.
 */

/* As with the interrupt register, we have two classes of timer registers
 * which are per-cpu and master.  Per-cpu timers only hit that cpu and are
 * only level 14 ticks, master timer hits all cpus and is level 10.
 */

#define SUN4M_PRM_CNT_L       0x80000000
#define SUN4M_PRM_CNT_LVALUE  0x7FFFFC00

struct sun4m_timer_percpu_info {
  __volatile__ unsigned int l14_timer_limit;    /* Initial value is 0x009c4000 */
  __volatile__ unsigned int l14_cur_count;

  /* This register appears to be write only and/or inaccessible
   * on Uni-Processor sun4m machines.
   */
  __volatile__ unsigned int l14_limit_noclear;  /* Data access error is here */

  __volatile__ unsigned int cntrl;            /* =1 after POST on Aurora */
  __volatile__ unsigned char space[PAGE_SIZE - 16];
};

struct sun4m_timer_regs {
	struct sun4m_timer_percpu_info cpu_timers[SUN4M_NCPUS];
	volatile unsigned int l10_timer_limit;
	volatile unsigned int l10_cur_count;

	/* Again, this appears to be write only and/or inaccessible
	 * on uni-processor sun4m machines.
	 */
	volatile unsigned int l10_limit_noclear;

	/* This register too, it must be magic. */
	volatile unsigned int foobar;

	volatile unsigned int cfg;     /* equals zero at boot time... */
};

#define SUN4D_PRM_CNT_L       0x80000000
#define SUN4D_PRM_CNT_LVALUE  0x7FFFFC00

+57 −64
Original line number Diff line number Diff line
@@ -267,95 +267,88 @@ static void sun4m_set_udt(int cpu)
}
#endif

struct sun4m_timer_percpu {
	u32		l14_limit;
	u32		l14_count;
	u32		l14_limit_noclear;
	u32		user_timer_start_stop;
};

static struct sun4m_timer_percpu __iomem *timers_percpu[SUN4M_NCPUS];

struct sun4m_timer_global {
	u32		l10_limit;
	u32		l10_count;
	u32		l10_limit_noclear;
	u32		reserved;
	u32		timer_config;
};

static struct sun4m_timer_global __iomem *timers_global;

#define OBIO_INTR	0x20
#define TIMER_IRQ  	(OBIO_INTR | 10)
#define PROFILE_IRQ	(OBIO_INTR | 14)

static struct sun4m_timer_regs *sun4m_timers;
unsigned int lvl14_resolution = (((1000000/HZ) + 1) << 10);

static void sun4m_clear_clock_irq(void)
{
	volatile unsigned int clear_intr;
	clear_intr = sun4m_timers->l10_timer_limit;
	sbus_readl(&timers_global->l10_limit);
}

static void sun4m_clear_profile_irq(int cpu)
{
	volatile unsigned int clear;
    
	clear = sun4m_timers->cpu_timers[cpu].l14_timer_limit;
	sbus_readl(&timers_percpu[cpu]->l14_limit);
}

static void sun4m_load_profile_irq(int cpu, unsigned int limit)
{
	sun4m_timers->cpu_timers[cpu].l14_timer_limit = limit;
	sbus_writel(limit, &timers_percpu[cpu]->l14_limit);
}

static void __init sun4m_init_timers(irq_handler_t counter_fn)
{
	int reg_count, irq, cpu;
	struct linux_prom_registers cnt_regs[PROMREG_MAX];
	int obio_node, cnt_node;
	struct resource r;
	struct device_node *dp = of_find_node_by_name(NULL, "counter");
	int i, err, len, num_cpu_timers;
	const u32 *addr;

	cnt_node = 0;
	if((obio_node =
	    prom_searchsiblings (prom_getchild(prom_root_node), "obio")) == 0 ||
	   (obio_node = prom_getchild (obio_node)) == 0 ||
	   (cnt_node = prom_searchsiblings (obio_node, "counter")) == 0) {
		prom_printf("Cannot find /obio/counter node\n");
		prom_halt();
	if (!dp) {
		printk(KERN_ERR "sun4m_init_timers: No 'counter' node.\n");
		return;
	}
	reg_count = prom_getproperty(cnt_node, "reg",
				     (void *) cnt_regs, sizeof(cnt_regs));
	reg_count = (reg_count/sizeof(struct linux_prom_registers));
    
	/* Apply the obio ranges to the timer registers. */
	prom_apply_obio_ranges(cnt_regs, reg_count);
    
	cnt_regs[4].phys_addr = cnt_regs[reg_count-1].phys_addr;
	cnt_regs[4].reg_size = cnt_regs[reg_count-1].reg_size;
	cnt_regs[4].which_io = cnt_regs[reg_count-1].which_io;
	for(obio_node = 1; obio_node < 4; obio_node++) {
		cnt_regs[obio_node].phys_addr =
			cnt_regs[obio_node-1].phys_addr + PAGE_SIZE;
		cnt_regs[obio_node].reg_size = cnt_regs[obio_node-1].reg_size;
		cnt_regs[obio_node].which_io = cnt_regs[obio_node-1].which_io;

	addr = of_get_property(dp, "address", &len);
	if (!addr) {
		printk(KERN_ERR "sun4m_init_timers: No 'address' prop.\n");
		return;
	}

	memset((char*)&r, 0, sizeof(struct resource));
	/* Map the per-cpu Counter registers. */
	r.flags = cnt_regs[0].which_io;
	r.start = cnt_regs[0].phys_addr;
	sun4m_timers = (struct sun4m_timer_regs *) of_ioremap(&r, 0,
	    PAGE_SIZE*SUN4M_NCPUS, "sun4m_cpu_cnt");
	/* Map the system Counter register. */
	/* XXX Here we expect consequent calls to yeld adjusent maps. */
	r.flags = cnt_regs[4].which_io;
	r.start = cnt_regs[4].phys_addr;
	of_ioremap(&r, 0, cnt_regs[4].reg_size, "sun4m_sys_cnt");

	sun4m_timers->l10_timer_limit =  (((1000000/HZ) + 1) << 10);
	master_l10_counter = &sun4m_timers->l10_cur_count;
	master_l10_limit = &sun4m_timers->l10_timer_limit;

	irq = request_irq(TIMER_IRQ,
			  counter_fn,
			  (IRQF_DISABLED | SA_STATIC_ALLOC),
			  "timer", NULL);
	if (irq) {
		prom_printf("time_init: unable to attach IRQ%d\n",TIMER_IRQ);
		prom_halt();
	num_cpu_timers = (len / sizeof(u32)) - 1;
	for (i = 0; i < num_cpu_timers; i++) {
		timers_percpu[i] = (void __iomem *)
			(unsigned long) addr[i];
	}
	timers_global = (void __iomem *)
		(unsigned long) addr[num_cpu_timers];

	if (!cpu_find_by_instance(1, NULL, NULL)) {
		for(cpu = 0; cpu < 4; cpu++)
			sun4m_timers->cpu_timers[cpu].l14_timer_limit = 0;
		sun4m_interrupts->set = SUN4M_INT_E14;
	} else {
		sun4m_timers->cpu_timers[0].l14_timer_limit = 0;
	sbus_writel((((1000000/HZ) + 1) << 10), &timers_global->l10_limit);

	master_l10_counter = &timers_global->l10_count;
	master_l10_limit = &timers_global->l10_limit;

	err = request_irq(TIMER_IRQ, counter_fn,
			  (IRQF_DISABLED | SA_STATIC_ALLOC), "timer", NULL);
	if (err) {
		printk(KERN_ERR "sun4m_init_timers: Register IRQ error %d.\n",
			err);
		return;
	}

	for (i = 0; i < num_cpu_timers; i++)
		sbus_writel(0, &timers_percpu[i]->l14_limit);
	if (num_cpu_timers == 4)
		sbus_writel(SUN4M_INT_E14, &sun4m_interrupts->set);

#ifdef CONFIG_SMP
	{
		unsigned long flags;