/*
 * Setup pointers to hardware-dependent routines.
 *
 * This file is subject to the terms and conditions of the GNU General Public
 * License.  See the file "COPYING" in the main directory of this archive
 * for more details.
 *
 * Copyright (C) 1996, 1997, 1998 by Ralf Baechle
 */
#include <linux/config.h>
#include <linux/hdreg.h>
#include <linux/init.h>
#include <linux/mm.h>
#include <linux/interrupt.h>
#include <linux/ide.h>
#include <linux/bootmem.h>
#include <asm/reboot.h>
#include <asm/time.h>
#include <asm/hp-lj/asic.h>
#include "utils.h"

extern char CommandLine[];
extern void pci_setup(void);

#ifdef CONFIG_KGDB
int remote_debug = 0;
#endif

const char *get_system_type(void)
{
	return "HP LaserJet";	/* But which exactly?  */
}

static void (*timer_interrupt_service) (int irq, void *dev_id,
					struct pt_regs * regs) = NULL;


static void andros_timer_interrupt(int irq, void *dev_id,
				   struct pt_regs *regs)
{
	if (!(*((volatile unsigned int *) 0xbfea0010) & 0x20))	// mask = pend & en
		return;

	/* clear timer interrupt */
	{
		unsigned int tmr = *((volatile unsigned int *) 0xbfe90040);	// ctl bits
		*((volatile unsigned int *) 0xbfe90040) = tmr;	// write to ack
		*((volatile unsigned int *) 0xbfea000c) = 0x20;	// sys int ack
	}

	/* service interrupt */
	timer_interrupt_service(irq, dev_id, regs);
}

static void harmony_timer_interrupt(int irq, void *dev_id,
				    struct pt_regs *regs)
{
	if (!(*((volatile unsigned int *) 0xbff63000) & 0x01))
		return;		// big sys     int reg, 01-timer  did it
	if (!(*((volatile unsigned int *) 0xbff610a4) & 0x01))
		return;		// local small int reg, 01-timer0 did it

	*((volatile unsigned int *) 0xbff610a4) = 1;	// ack local timer0 bit
	*((volatile unsigned int *) 0xbff63000) = 1;	// ack global timer bit

	/* service interrupt */
	timer_interrupt_service(irq, dev_id, regs);
}


#define ASIC_IRQ_NUMBER  2


static void __init hp_time_init(struct irqaction *irq)
{
	timer_interrupt_service = irq->handler;

	if (GetAsicId() == AndrosAsic) {
		//*((volatile unsigned int*)0xbfe90000) = 0x2f;  // set by bootloader to 0x20              // prescaler
		*((volatile unsigned int *) 0xbfe90040) = 0x21;	// 20-res of 1kHz,1-int ack                // control
		*((volatile unsigned int *) 0xbfe90048) = 0x09;	// 09-reload val                          // reload
		*((volatile unsigned int *) 0xbfe90044) = 0x09;	// 09-count val                           // count
		*((volatile unsigned int *) 0xbfe90040) = 0x2f;	// 8-int enable,4-reload en,2-count down en,1-int-ack

		irq->handler = andros_timer_interrupt;
		irq->flags |= SA_INTERRUPT | SA_SHIRQ;
		printk("setting up timer in hp_time_init\n");
		setup_irq(ASIC_IRQ_NUMBER, irq);

		// enable timer interrupt
		*((volatile unsigned int *) 0xbfea0000) = 0x20;

	} else if (GetAsicId() == HarmonyAsic) {

		*((volatile unsigned int *) 0xbff61000) = 99;	// prescaler, 100Mz sys clk
		*((volatile unsigned int *) 0xbff61028) = 0x09;	// reload reg
		*((volatile unsigned int *) 0xbff61024) = 0x09;	// count reg
		*((volatile unsigned int *) 0xbff61020) = 0x0b;	// 80-1khz res on timer, 2 reload en, 1 - count down en

		irq->handler = harmony_timer_interrupt;
		irq->flags |= SA_INTERRUPT | SA_SHIRQ;
		setup_irq(ASIC_IRQ_NUMBER, irq);

		*((volatile unsigned int *) 0xbff610a0) |= 1;	// turn on timer0

	} else if (GetAsicId() == UnknownAsic)
		printk("Unknown asic in hp_time_init()\n");
	else
		printk("Unsupported asic in hp_time_init()\n");
}


static void hplj_restart(void)
{
	if (GetAsicId() == AndrosAsic)
		*((volatile unsigned int *) 0xbfe900c0) = 0;


	if (GetAsicId() == HarmonyAsic)
		*((volatile unsigned int *) 0xbff62030) = 0;

	printk("Restart Failed ... halting instead\n");
	while (1);
}

static void hplj_halt(void)
{
	while (1);
}

static void __init hp_setup(void)
{
#ifdef CONFIG_PCI
	pci_setup();
#endif

	_machine_restart = (void (*)(char *)) hplj_restart;
	_machine_halt = hplj_halt;
	_machine_power_off = hplj_halt;

	board_timer_setup = hp_time_init;

#ifdef CONFIG_KGDB
	remote_debug = (strstr(CommandLine, "kgdb") != NULL);
#endif

	printk("HP SETUP\n");
}

early_initcall(hp_setup);
