示例#1
0
int gsc_common_setup(struct parisc_device *parent, struct gsc_asic *gsc_asic)
{
	struct resource *res;
	int i;

	gsc_asic->gsc = parent;

	/* Initialise local irq -> global irq mapping */
	for (i = 0; i < 32; i++) {
		gsc_asic->global_irq[i] = NO_IRQ;
	}

	/* allocate resource region */
	res = request_mem_region(gsc_asic->hpa, 0x100000, gsc_asic->name);
	if (res) {
		res->flags = IORESOURCE_MEM; 	/* do not mark it busy ! */
	}

#if 0
	printk(KERN_WARNING "%s IRQ %d EIM 0x%x", gsc_asic->name,
			parent->irq, gsc_asic->eim);
	if (gsc_readl(gsc_asic->hpa + OFFSET_IMR))
		printk("  IMR is non-zero! (0x%x)",
				gsc_readl(gsc_asic->hpa + OFFSET_IMR));
	printk("\n");
#endif

	return 0;
}
static int __init lasi_init_chip(struct parisc_device *dev)
{
	extern void (*chassis_power_off)(void);
	struct gsc_asic *lasi;
	struct gsc_irq gsc_irq;
	int ret;

	lasi = kzalloc(sizeof(*lasi), GFP_KERNEL);
	if (!lasi)
		return -ENOMEM;

	lasi->name = "Lasi";
	lasi->hpa = dev->hpa.start;

	
	lasi->version = gsc_readl(lasi->hpa + LASI_VER) & 0xf;
	printk(KERN_INFO "%s version %d at 0x%lx found.\n",
		lasi->name, lasi->version, lasi->hpa);

	 
	lasi_led_init(lasi->hpa);

	
	lasi_init_irq(lasi);

	
	dev->irq = gsc_alloc_irq(&gsc_irq);
	if (dev->irq < 0) {
		printk(KERN_ERR "%s(): cannot get GSC irq\n",
				__func__);
		kfree(lasi);
		return -EBUSY;
	}

	lasi->eim = ((u32) gsc_irq.txn_addr) | gsc_irq.txn_data;

	ret = request_irq(gsc_irq.irq, gsc_asic_intr, 0, "lasi", lasi);
	if (ret < 0) {
		kfree(lasi);
		return ret;
	}

	
	gsc_writel(lasi->eim, lasi->hpa + OFFSET_IAR);

	
	ret = gsc_common_setup(dev, lasi);
	if (ret) {
		kfree(lasi);
		return ret;
	}    

	gsc_fixup_irqs(dev, lasi, lasi_choose_irq);

	
	lasi_power_off_hpa = lasi->hpa;
	chassis_power_off = lasi_power_off;
	
	return ret;
}
示例#3
0
static void __init
lasi_init_irq(struct gsc_asic *this_lasi)
{
	unsigned long lasi_base = this_lasi->hpa;

	/* Stop LASI barking for a bit */
	gsc_writel(0x00000000, lasi_base+OFFSET_IMR);

	/* clear pending interrupts */
	gsc_readl(lasi_base+OFFSET_IRR);

	/* We're not really convinced we want to reset the onboard
         * devices. Firmware does it for us...
	 */

	/* Resets */
	/* gsc_writel(0xFFFFFFFF, lasi_base+0x2000);*/	/* Parallel */
	if(pdc_add_valid(lasi_base+0x4004) == PDC_OK)
		gsc_writel(0xFFFFFFFF, lasi_base+0x4004);	/* Audio */
	/* gsc_writel(0xFFFFFFFF, lasi_base+0x5000);*/	/* Serial */ 
	/* gsc_writel(0xFFFFFFFF, lasi_base+0x6000);*/	/* SCSI */
	gsc_writel(0xFFFFFFFF, lasi_base+0x7000);	/* LAN */
	gsc_writel(0xFFFFFFFF, lasi_base+0x8000);	/* Keyboard */
	gsc_writel(0xFFFFFFFF, lasi_base+0xA000);	/* FDC */
	
	/* Ok we hit it on the head with a hammer, our Dog is now
	** comatose and muzzled.  Devices will now unmask LASI
	** interrupts as they are registered as irq's in the LASI range.
	*/
	/* XXX: I thought it was `awks that got `it on the `ead with an
	 * `ammer.  -- willy
	 */
}
示例#4
0
static int __init lasi_init_chip(struct parisc_device *dev)
{
	extern void (*chassis_power_off)(void);
	struct gsc_asic *lasi;
	struct gsc_irq gsc_irq;
	int ret;

	lasi = kzalloc(sizeof(*lasi), GFP_KERNEL);
	if (!lasi)
		return -ENOMEM;

	lasi->name = "Lasi";
	lasi->hpa = dev->hpa.start;

	/* Check the 4-bit (yes, only 4) version register */
	lasi->version = gsc_readl(lasi->hpa + LASI_VER) & 0xf;
	printk(KERN_INFO "%s version %d at 0x%lx found.\n",
		lasi->name, lasi->version, lasi->hpa);

	/* initialize the chassis LEDs really early */ 
	lasi_led_init(lasi->hpa);

	/* Stop LASI barking for a bit */
	lasi_init_irq(lasi);

	/* the IRQ lasi should use */
	dev->irq = gsc_alloc_irq(&gsc_irq);
	if (dev->irq < 0) {
		printk(KERN_ERR "%s(): cannot get GSC irq\n",
				__func__);
		kfree(lasi);
		return -EBUSY;
	}

	lasi->eim = ((u32) gsc_irq.txn_addr) | gsc_irq.txn_data;

	ret = request_irq(gsc_irq.irq, gsc_asic_intr, 0, "lasi", lasi);
	if (ret < 0) {
		kfree(lasi);
		return ret;
	}

	/* enable IRQ's for devices below LASI */
	gsc_writel(lasi->eim, lasi->hpa + OFFSET_IAR);

	/* Done init'ing, register this driver */
	ret = gsc_common_setup(dev, lasi);
	if (ret) {
		kfree(lasi);
		return ret;
	}    

	gsc_fixup_irqs(dev, lasi, lasi_choose_irq);

	/* initialize the power off function */
	lasi_power_off_hpa = lasi->hpa;
	chassis_power_off = lasi_power_off;
	
	return ret;
}
示例#5
0
文件: gsc.c 项目: ANFS/ANFS-kernel
static void gsc_asic_mask_irq(unsigned int irq)
{
	struct gsc_asic *irq_dev = get_irq_chip_data(irq);
	int local_irq = gsc_find_local_irq(irq, irq_dev->global_irq, 32);
	u32 imr;

	DEBPRINTK(KERN_DEBUG "%s(%d) %s: IMR 0x%x\n", __func__, irq,
			irq_dev->name, imr);

	/* Disable the IRQ line by clearing the bit in the IMR */
	imr = gsc_readl(irq_dev->hpa + OFFSET_IMR);
	imr &= ~(1 << local_irq);
	gsc_writel(imr, irq_dev->hpa + OFFSET_IMR);
}
示例#6
0
文件: gsc.c 项目: 3sOx/asuswrt-merlin
static void gsc_asic_enable_irq(unsigned int irq)
{
	struct irq_desc *desc = irq_to_desc(irq);
	struct gsc_asic *irq_dev = desc->chip_data;
	int local_irq = gsc_find_local_irq(irq, irq_dev->global_irq, 32);
	u32 imr;

	DEBPRINTK(KERN_DEBUG "%s(%d) %s: IMR 0x%x\n", __func__, irq,
			irq_dev->name, imr);

	/* Enable the IRQ line by setting the bit in the IMR */
	imr = gsc_readl(irq_dev->hpa + OFFSET_IMR);
	imr |= 1 << local_irq;
	gsc_writel(imr, irq_dev->hpa + OFFSET_IMR);
}
示例#7
0
static void polling_tasklet_func(unsigned long soft_power_reg)
{
        unsigned long current_status;
	
	if (!pwrsw_enabled)
		return;

	current_status = gsc_readl(soft_power_reg);
	if (current_status & 0x1) {
		/* power switch button not pressed */
		shutdown_timer = 0;
	} else {
		process_shutdown();
	}
}
示例#8
0
/* main kernel thread worker. It polls the button state */
static int kpowerswd(void *param)
{
	__set_current_state(TASK_RUNNING);

	do {
		int button_not_pressed;
		unsigned long soft_power_reg = (unsigned long) param;

		schedule_timeout_interruptible(pwrsw_enabled ? HZ : HZ/POWERSWITCH_POLL_PER_SEC);
		__set_current_state(TASK_RUNNING);

		if (unlikely(!pwrsw_enabled))
			continue;

		if (soft_power_reg) {
			/*
			 * Non-Gecko-style machines:
			 * Check the power switch status which is read from the
			 * real I/O location at soft_power_reg.
			 * Bit 31 ("the lowest bit) is the status of the power switch.
			 * This bit is "1" if the button is NOT pressed.
			 */
			button_not_pressed = (gsc_readl(soft_power_reg) & 0x1);
		} else {
			/*
			 * On gecko style machines (e.g. 712/xx and 715/xx) 
			 * the power switch status is stored in Bit 0 ("the highest bit")
			 * of CPU diagnose register 25.
			 * Warning: Some machines never reset the DIAG flag, even if
			 * the button has been released again.
			 */
			button_not_pressed = (__getDIAG(25) & 0x80000000);
		}

		if (likely(button_not_pressed)) {
			if (unlikely(shutdown_timer && /* avoid writing if not necessary */
				shutdown_timer < (POWERSWITCH_DOWN_SEC*POWERSWITCH_POLL_PER_SEC))) {
				shutdown_timer = 0;
				printk(KERN_INFO KTHREAD_NAME ": Shutdown request aborted.\n");
			}
		} else
			process_shutdown();


	} while (!kthread_should_stop());

	return 0;
}
示例#9
0
static int kpowerswd(void *param)
{
	__set_current_state(TASK_RUNNING);

	do {
		int button_not_pressed;
		unsigned long soft_power_reg = (unsigned long) param;

		schedule_timeout_interruptible(pwrsw_enabled ? HZ : HZ/POWERSWITCH_POLL_PER_SEC);
		__set_current_state(TASK_RUNNING);

		if (unlikely(!pwrsw_enabled))
			continue;

		if (soft_power_reg) {
			/*
                               
                                                          
                                          
                                                                 
                                                   
    */
			button_not_pressed = (gsc_readl(soft_power_reg) & 0x1);
		} else {
			/*
                                                       
                                                                    
                                  
                                                               
                                         
    */
			button_not_pressed = (__getDIAG(25) & 0x80000000);
		}

		if (likely(button_not_pressed)) {
			if (unlikely(shutdown_timer && /*                                */
				shutdown_timer < (POWERSWITCH_DOWN_SEC*POWERSWITCH_POLL_PER_SEC))) {
				shutdown_timer = 0;
				printk(KERN_INFO KTHREAD_NAME ": Shutdown request aborted.\n");
			}
		} else
			process_shutdown();


	} while (!kthread_should_stop());

	return 0;
}
示例#10
0
文件: gsc.c 项目: ANFS/ANFS-kernel
static void gsc_asic_unmask_irq(unsigned int irq)
{
	struct gsc_asic *irq_dev = get_irq_chip_data(irq);
	int local_irq = gsc_find_local_irq(irq, irq_dev->global_irq, 32);
	u32 imr;

	DEBPRINTK(KERN_DEBUG "%s(%d) %s: IMR 0x%x\n", __func__, irq,
			irq_dev->name, imr);

	/* Enable the IRQ line by setting the bit in the IMR */
	imr = gsc_readl(irq_dev->hpa + OFFSET_IMR);
	imr |= 1 << local_irq;
	gsc_writel(imr, irq_dev->hpa + OFFSET_IMR);
	/*
	 * FIXME: read IPR to make sure the IRQ isn't already pending.
	 *   If so, we need to read IRR and manually call do_irq().
	 */
}
示例#11
0
文件: wax.c 项目: 020gzh/linux
static void __init
wax_init_irq(struct gsc_asic *wax)
{
	unsigned long base = wax->hpa;

	/* Wax-off */
	gsc_writel(0x00000000, base+OFFSET_IMR);

	/* clear pending interrupts */
	gsc_readl(base+OFFSET_IRR);

	/* We're not really convinced we want to reset the onboard
         * devices. Firmware does it for us...
	 */

	/* Resets */
//	gsc_writel(0xFFFFFFFF, base+0x1000); /* HIL */
//	gsc_writel(0xFFFFFFFF, base+0x2000); /* RS232-B on Wax */
}
示例#12
0
static void __init
wax_init_irq(struct gsc_asic *wax)
{
	unsigned long base = wax->hpa;

	/*         */
	gsc_writel(0x00000000, base+OFFSET_IMR);

	/*                          */
	gsc_readl(base+OFFSET_IRR);

	/*                                                        
                                              
  */

	/*        */
//                                               
//                                                          
}
示例#13
0
/* Common interrupt demultiplexer used by Asp, Lasi & Wax.  */
irqreturn_t gsc_asic_intr(int gsc_asic_irq, void *dev)
{
	unsigned long irr;
	struct gsc_asic *gsc_asic = dev;

	irr = gsc_readl(gsc_asic->hpa + OFFSET_IRR);
	if (irr == 0)
		return IRQ_NONE;

	DEBPRINTK("%s intr, mask=0x%x\n", gsc_asic->name, irr);

	do {
		int local_irq = __ffs(irr);
		unsigned int irq = gsc_asic->global_irq[local_irq];
		__do_IRQ(irq);
		irr &= ~(1 << local_irq);
	} while (irr);

	return IRQ_HANDLED;
}
static void pa7300lc_lpmc(int code, struct pt_regs *regs)
{
	u32 hpa;
	printk(KERN_WARNING "LPMC on CPU %d\n", smp_processor_id());

	show_regs(regs);

	hpa = cpu_hpa();
	printk(KERN_WARNING
		"MIOC_CONTROL %08x\n" "MIOC_STATUS  %08x\n"
		"MDERRADD     %08x\n" "DMAERR       %08x\n"
		"DIOERR       %08x\n" "HIDMAMEM     %08x\n",
		gsc_readl(hpa+MIOC_CONTROL), gsc_readl(hpa+MIOC_STATUS),
		gsc_readl(hpa+MDERRADD), gsc_readl(hpa+DMAERR),
		gsc_readl(hpa+DIOERR), gsc_readl(hpa+HIDMAMEM));
}
示例#15
0
static void __init
lasi_init_irq(struct gsc_asic *this_lasi)
{
	unsigned long lasi_base = this_lasi->hpa;

	
	gsc_writel(0x00000000, lasi_base+OFFSET_IMR);

	
	gsc_readl(lasi_base+OFFSET_IRR);


	
		
	if(pdc_add_valid(lasi_base+0x4004) == PDC_OK)
		gsc_writel(0xFFFFFFFF, lasi_base+0x4004);	
		 
		
	gsc_writel(0xFFFFFFFF, lasi_base+0x7000);	
	gsc_writel(0xFFFFFFFF, lasi_base+0x8000);	
	gsc_writel(0xFFFFFFFF, lasi_base+0xA000);	
	
}
示例#16
0
void
sti_putc(struct sti_struct *sti, int c, int y, int x)
{
	struct sti_font_inptr inptr = {
		.font_start_addr= STI_PTR(sti->font->raw),
		.index		= c_index(sti, c),
		.fg_color	= c_fg(sti, c),
		.bg_color	= c_bg(sti, c),
		.dest_x		= x * sti->font_width,
		.dest_y		= y * sti->font_height,
	};
	struct sti_font_outptr outptr = { 0, };
	s32 ret;
	unsigned long flags;

	do {
		spin_lock_irqsave(&sti->lock, flags);
		ret = STI_CALL(sti->font_unpmv, &default_font_flags,
			&inptr, &outptr, sti->glob_cfg);
		spin_unlock_irqrestore(&sti->lock, flags);
	} while (ret == 1);
}

static const struct sti_blkmv_flags clear_blkmv_flags = {
	.wait	= STI_WAIT, 
	.color	= 1, 
	.clear	= 1, 
};

void
sti_set(struct sti_struct *sti, int src_y, int src_x,
	int height, int width, u8 color)
{
	struct sti_blkmv_inptr inptr = {
		.fg_color	= color,
		.bg_color	= color,
		.src_x		= src_x,
		.src_y		= src_y,
		.dest_x		= src_x,
		.dest_y		= src_y,
		.width		= width,
		.height		= height,
	};
	struct sti_blkmv_outptr outptr = { 0, };
	s32 ret;
	unsigned long flags;
	
	do {
		spin_lock_irqsave(&sti->lock, flags);
		ret = STI_CALL(sti->block_move, &clear_blkmv_flags,
			&inptr, &outptr, sti->glob_cfg);
		spin_unlock_irqrestore(&sti->lock, flags);
	} while (ret == 1);
}

void
sti_clear(struct sti_struct *sti, int src_y, int src_x,
	  int height, int width, int c)
{
	struct sti_blkmv_inptr inptr = {
		.fg_color	= c_fg(sti, c),
		.bg_color	= c_bg(sti, c),
		.src_x		= src_x * sti->font_width,
		.src_y		= src_y * sti->font_height,
		.dest_x		= src_x * sti->font_width,
		.dest_y		= src_y * sti->font_height,
		.width		= width * sti->font_width,
		.height		= height* sti->font_height,
	};
	struct sti_blkmv_outptr outptr = { 0, };
	s32 ret;
	unsigned long flags;

	do {
		spin_lock_irqsave(&sti->lock, flags);
		ret = STI_CALL(sti->block_move, &clear_blkmv_flags,
			&inptr, &outptr, sti->glob_cfg);
		spin_unlock_irqrestore(&sti->lock, flags);
	} while (ret == 1);
}

static const struct sti_blkmv_flags default_blkmv_flags = {
	.wait = STI_WAIT, 
};

void
sti_bmove(struct sti_struct *sti, int src_y, int src_x,
	  int dst_y, int dst_x, int height, int width)
{
	struct sti_blkmv_inptr inptr = {
		.src_x		= src_x * sti->font_width,
		.src_y		= src_y * sti->font_height,
		.dest_x		= dst_x * sti->font_width,
		.dest_y		= dst_y * sti->font_height,
		.width		= width * sti->font_width,
		.height		= height* sti->font_height,
	};
	struct sti_blkmv_outptr outptr = { 0, };
	s32 ret;
	unsigned long flags;

	do {
		spin_lock_irqsave(&sti->lock, flags);
		ret = STI_CALL(sti->block_move, &default_blkmv_flags,
			&inptr, &outptr, sti->glob_cfg);
		spin_unlock_irqrestore(&sti->lock, flags);
	} while (ret == 1);
}


static void sti_flush(unsigned long start, unsigned long end)
{
	flush_icache_range(start, end);
}

static void __devinit sti_rom_copy(unsigned long base, unsigned long count,
				   void *dest)
{
	unsigned long dest_start = (unsigned long) dest;

	/* this still needs to be revisited (see arch/parisc/mm/init.c:246) ! */
	while (count >= 4) {
		count -= 4;
		*(u32 *)dest = gsc_readl(base);
		base += 4;
		dest += 4;
	}
	while (count) {
		count--;
		*(u8 *)dest = gsc_readb(base);
		base++;
		dest++;
	}

	sti_flush(dest_start, (unsigned long)dest);
}




static char default_sti_path[21] __read_mostly;

#ifndef MODULE
static int __devinit sti_setup(char *str)
{
	if (str)
		strlcpy (default_sti_path, str, sizeof (default_sti_path));
	
	return 1;
}

__setup("sti=", sti_setup);
#endif



static char __devinitdata	*font_name[MAX_STI_ROMS] = { "VGA8x16", };
static int __devinitdata	font_index[MAX_STI_ROMS],
				font_height[MAX_STI_ROMS],
				font_width[MAX_STI_ROMS];
#ifndef MODULE
static int __devinit sti_font_setup(char *str)
{
	char *x;
	int i = 0;

	/* we accept sti_font=VGA8x16, sti_font=10x20, sti_font=10*20 
	 * or sti_font=7 style command lines. */

	while (i<MAX_STI_ROMS && str && *str) {
		if (*str>='0' && *str<='9') {
			if ((x = strchr(str, 'x')) || (x = strchr(str, '*'))) {
				font_height[i] = simple_strtoul(str, NULL, 0);
				font_width[i] = simple_strtoul(x+1, NULL, 0);
			} else {
				font_index[i] = simple_strtoul(str, NULL, 0);
			}
		} else {
			font_name[i] = str;	/* fb font name */
		}

		if ((x = strchr(str, ',')))
			*x++ = 0;
		str = x;

		i++;
	}

	return 1;
}

__setup("sti_font=", sti_font_setup);
#endif


	
static void __devinit
sti_dump_globcfg(struct sti_glob_cfg *glob_cfg, unsigned int sti_mem_request)
{
	struct sti_glob_cfg_ext *cfg;
	
	DPRINTK((KERN_INFO
		"%d text planes\n"
		"%4d x %4d screen resolution\n"
		"%4d x %4d offscreen\n"
		"%4d x %4d layout\n"
		"regions at %08x %08x %08x %08x\n"
		"regions at %08x %08x %08x %08x\n"
		"reent_lvl %d\n"
		"save_addr %08x\n",
		glob_cfg->text_planes,
		glob_cfg->onscreen_x, glob_cfg->onscreen_y,
		glob_cfg->offscreen_x, glob_cfg->offscreen_y,
		glob_cfg->total_x, glob_cfg->total_y,
		glob_cfg->region_ptrs[0], glob_cfg->region_ptrs[1],
		glob_cfg->region_ptrs[2], glob_cfg->region_ptrs[3],
		glob_cfg->region_ptrs[4], glob_cfg->region_ptrs[5],
		glob_cfg->region_ptrs[6], glob_cfg->region_ptrs[7],
		glob_cfg->reent_lvl,
		glob_cfg->save_addr));

	/* dump extended cfg */ 
	cfg = PTR_STI((unsigned long)glob_cfg->ext_ptr);
	DPRINTK(( KERN_INFO
		"monitor %d\n"
		"in friendly mode: %d\n"
		"power consumption %d watts\n"
		"freq ref %d\n"
		"sti_mem_addr %08x (size=%d bytes)\n",
		cfg->curr_mon,
		cfg->friendly_boot,
		cfg->power,
		cfg->freq_ref,
		cfg->sti_mem_addr, sti_mem_request));
}

static void __devinit
sti_dump_outptr(struct sti_struct *sti)
{
	DPRINTK((KERN_INFO
		"%d bits per pixel\n"
		"%d used bits\n"
		"%d planes\n"
		"attributes %08x\n",
		 sti->outptr.bits_per_pixel,
		 sti->outptr.bits_used,
		 sti->outptr.planes,
		 sti->outptr.attributes));
}
示例#17
0
int __init
lasi_init_chip(struct parisc_device *dev)
{
	struct busdevice *lasi;
	struct gsc_irq gsc_irq;
	int irq, ret;

	lasi = kmalloc(sizeof(struct busdevice), GFP_KERNEL);
	if (!lasi)
		return -ENOMEM;

	lasi->name = "Lasi";
	lasi->hpa = dev->hpa;

	/* Check the 4-bit (yes, only 4) version register */
	lasi->version = gsc_readl(lasi->hpa + LASI_VER) & 0xf;
	printk(KERN_INFO "%s version %d at 0x%lx found.\n",
		lasi->name, lasi->version, lasi->hpa);

	/* initialize the chassis LEDs really early */ 
	lasi_led_init(lasi->hpa);

	/* Stop LASI barking for a bit */
	lasi_init_irq(lasi);

	/* the IRQ lasi should use */
	irq = gsc_alloc_irq(&gsc_irq);
	if (irq < 0) {
		printk(KERN_ERR "%s(): cannot get GSC irq\n",
				__FUNCTION__);
		kfree(lasi);
		return -EBUSY;
	}

	ret = request_irq(gsc_irq.irq, busdev_barked, 0, "lasi", lasi);
	if (ret < 0) {
		kfree(lasi);
		return ret;
	}

	/* Save this for debugging later */
	lasi->parent_irq = gsc_irq.irq;
	lasi->eim = ((u32) gsc_irq.txn_addr) | gsc_irq.txn_data;

	/* enable IRQ's for devices below LASI */
	gsc_writel(lasi->eim, lasi->hpa + OFFSET_IAR);

	/* Done init'ing, register this driver */
	ret = gsc_common_irqsetup(dev, lasi);
	if (ret) {
		kfree(lasi);
		return ret;
	}    

	fixup_child_irqs(dev, lasi->busdev_region->data.irqbase,
			lasi_choose_irq);

	/* initialize the power off function */
	/* FIXME: Record the LASI HPA for the power off function.  This should
	 * ensure that only the first LASI (the one controlling the power off)
	 * should set the HPA here */
	lasi_power_off_hpa = lasi->hpa;
	pm_power_off = lasi_power_off;
	
	return ret;
}
示例#18
0
void
sti_putc(struct sti_struct *sti, int c, int y, int x)
{
	struct sti_font_inptr inptr = {
		.font_start_addr= STI_PTR(sti->font->raw),
		.index		= c_index(sti, c),
		.fg_color	= c_fg(sti, c),
		.bg_color	= c_bg(sti, c),
		.dest_x		= x * sti->font_width,
		.dest_y		= y * sti->font_height,
	};
	struct sti_font_outptr outptr = { 0, };
	s32 ret;
	unsigned long flags;

	do {
		spin_lock_irqsave(&sti->lock, flags);
		ret = STI_CALL(sti->font_unpmv, &default_font_flags,
			&inptr, &outptr, sti->glob_cfg);
		spin_unlock_irqrestore(&sti->lock, flags);
	} while (ret == 1);
}

static const struct sti_blkmv_flags clear_blkmv_flags = {
	.wait	= STI_WAIT, 
	.color	= 1, 
	.clear	= 1, 
};

void
sti_set(struct sti_struct *sti, int src_y, int src_x,
	int height, int width, u8 color)
{
	struct sti_blkmv_inptr inptr = {
		.fg_color	= color,
		.bg_color	= color,
		.src_x		= src_x,
		.src_y		= src_y,
		.dest_x		= src_x,
		.dest_y		= src_y,
		.width		= width,
		.height		= height,
	};
	struct sti_blkmv_outptr outptr = { 0, };
	s32 ret;
	unsigned long flags;
	
	do {
		spin_lock_irqsave(&sti->lock, flags);
		ret = STI_CALL(sti->block_move, &clear_blkmv_flags,
			&inptr, &outptr, sti->glob_cfg);
		spin_unlock_irqrestore(&sti->lock, flags);
	} while (ret == 1);
}

void
sti_clear(struct sti_struct *sti, int src_y, int src_x,
	  int height, int width, int c)
{
	struct sti_blkmv_inptr inptr = {
		.fg_color	= c_fg(sti, c),
		.bg_color	= c_bg(sti, c),
		.src_x		= src_x * sti->font_width,
		.src_y		= src_y * sti->font_height,
		.dest_x		= src_x * sti->font_width,
		.dest_y		= src_y * sti->font_height,
		.width		= width * sti->font_width,
		.height		= height* sti->font_height,
	};
	struct sti_blkmv_outptr outptr = { 0, };
	s32 ret;
	unsigned long flags;

	do {
		spin_lock_irqsave(&sti->lock, flags);
		ret = STI_CALL(sti->block_move, &clear_blkmv_flags,
			&inptr, &outptr, sti->glob_cfg);
		spin_unlock_irqrestore(&sti->lock, flags);
	} while (ret == 1);
}

static const struct sti_blkmv_flags default_blkmv_flags = {
	.wait = STI_WAIT, 
};

void
sti_bmove(struct sti_struct *sti, int src_y, int src_x,
	  int dst_y, int dst_x, int height, int width)
{
	struct sti_blkmv_inptr inptr = {
		.src_x		= src_x * sti->font_width,
		.src_y		= src_y * sti->font_height,
		.dest_x		= dst_x * sti->font_width,
		.dest_y		= dst_y * sti->font_height,
		.width		= width * sti->font_width,
		.height		= height* sti->font_height,
	};
	struct sti_blkmv_outptr outptr = { 0, };
	s32 ret;
	unsigned long flags;

	do {
		spin_lock_irqsave(&sti->lock, flags);
		ret = STI_CALL(sti->block_move, &default_blkmv_flags,
			&inptr, &outptr, sti->glob_cfg);
		spin_unlock_irqrestore(&sti->lock, flags);
	} while (ret == 1);
}


/* FIXME: Do we have another solution for this ? */
static void sti_flush(unsigned long from, unsigned long len)
{
	flush_data_cache();
	flush_kernel_dcache_range(from, len);
	flush_icache_range(from, from+len);
}

void __init
sti_rom_copy(unsigned long base, unsigned long count, void *dest)
{
	unsigned long dest_len = count;
	unsigned long dest_start = (unsigned long) dest;

	/* this still needs to be revisited (see arch/parisc/mm/init.c:246) ! */
	while (count >= 4) {
		count -= 4;
		*(u32 *)dest = gsc_readl(base);
		base += 4;
		dest += 4;
	}
	while (count) {
		count--;
		*(u8 *)dest = gsc_readb(base);
		base++;
		dest++;
	}

	sti_flush(dest_start, dest_len);
}




static char default_sti_path[21] __read_mostly;

#ifndef MODULE
static int __init sti_setup(char *str)
{
	if (str)
		strlcpy (default_sti_path, str, sizeof (default_sti_path));
	
	return 1;
}

/*	Assuming the machine has multiple STI consoles (=graphic cards) which
 *	all get detected by sticon, the user may define with the linux kernel
 *	parameter sti=<x> which of them will be the initial boot-console.
 *	<x> is a number between 0 and MAX_STI_ROMS, with 0 as the default 
 *	STI screen.
 */
__setup("sti=", sti_setup);
#endif



static char __initdata	*font_name[MAX_STI_ROMS] = { "VGA8x16", };
static int __initdata	font_index[MAX_STI_ROMS], 
			font_height[MAX_STI_ROMS],
			font_width[MAX_STI_ROMS];
#ifndef MODULE
static int __init sti_font_setup(char *str)
{
	char *x;
	int i = 0;

	/* we accept sti_font=VGA8x16, sti_font=10x20, sti_font=10*20 
	 * or sti_font=7 style command lines. */

	while (i<MAX_STI_ROMS && str && *str) {
		if (*str>='0' && *str<='9') {
			if ((x = strchr(str, 'x')) || (x = strchr(str, '*'))) {
				font_height[i] = simple_strtoul(str, NULL, 0);
				font_width[i] = simple_strtoul(x+1, NULL, 0);
			} else {
				font_index[i] = simple_strtoul(str, NULL, 0);
			}
		} else {
			font_name[i] = str;	/* fb font name */
		}

		if ((x = strchr(str, ',')))
			*x++ = 0;
		str = x;

		i++;
	}

	return 1;
}

/*	The optional linux kernel parameter "sti_font" defines which font
 *	should be used by the sticon driver to draw characters to the screen.
 *	Possible values are:
 *	- sti_font=<fb_fontname>:
 *		<fb_fontname> is the name of one of the linux-kernel built-in 
 *		framebuffer font names (e.g. VGA8x16, SUN22x18). 
 *		This is only available if the fonts have been statically compiled 
 *		in with e.g. the CONFIG_FONT_8x16 or CONFIG_FONT_SUN12x22 options.
 *	- sti_font=<number>
 *		most STI ROMs have built-in HP specific fonts, which can be selected
 *		by giving the desired number to the sticon driver. 
 *		NOTE: This number is machine and STI ROM dependend.
 *	- sti_font=<height>x<width>  (e.g. sti_font=16x8)
 *		<height> and <width> gives hints to the height and width of the
 *		font which the user wants. The sticon driver will try to use
 *		a font with this height and width, but if no suitable font is
 *		found, sticon will use the default 8x8 font.
 */
__setup("sti_font=", sti_font_setup);
#endif


	
static void __init
sti_dump_globcfg(struct sti_glob_cfg *glob_cfg, unsigned int sti_mem_request)
{
	struct sti_glob_cfg_ext *cfg;
	
	DPRINTK((KERN_INFO
		"%d text planes\n"
		"%4d x %4d screen resolution\n"
		"%4d x %4d offscreen\n"
		"%4d x %4d layout\n"
		"regions at %08x %08x %08x %08x\n"
		"regions at %08x %08x %08x %08x\n"
		"reent_lvl %d\n"
		"save_addr %08x\n",
		glob_cfg->text_planes,
		glob_cfg->onscreen_x, glob_cfg->onscreen_y,
		glob_cfg->offscreen_x, glob_cfg->offscreen_y,
		glob_cfg->total_x, glob_cfg->total_y,
		glob_cfg->region_ptrs[0], glob_cfg->region_ptrs[1],
		glob_cfg->region_ptrs[2], glob_cfg->region_ptrs[3],
		glob_cfg->region_ptrs[4], glob_cfg->region_ptrs[5],
		glob_cfg->region_ptrs[6], glob_cfg->region_ptrs[7],
		glob_cfg->reent_lvl,
		glob_cfg->save_addr));

	/* dump extended cfg */ 
	cfg = PTR_STI((unsigned long)glob_cfg->ext_ptr);
	DPRINTK(( KERN_INFO
		"monitor %d\n"
		"in friendly mode: %d\n"
		"power consumption %d watts\n"
		"freq ref %d\n"
		"sti_mem_addr %08x (size=%d bytes)\n",
		cfg->curr_mon,
		cfg->friendly_boot,
		cfg->power,
		cfg->freq_ref,
		cfg->sti_mem_addr, sti_mem_request));
}

static void __init
sti_dump_outptr(struct sti_struct *sti)
{
	DPRINTK((KERN_INFO
		"%d bits per pixel\n"
		"%d used bits\n"
		"%d planes\n"
		"attributes %08x\n",
		 sti->outptr.bits_per_pixel,
		 sti->outptr.bits_used,
		 sti->outptr.planes,
		 sti->outptr.attributes));
}