OpenCores
URL https://opencores.org/ocsvn/or1k/or1k/trunk

Subversion Repositories or1k

Compare Revisions

  • This comparison shows the changes necessary to convert path
    /or1k/trunk/linux/linux-2.4/arch/m68k/q40
    from Rev 1275 to Rev 1765
    Reverse comparison

Rev 1275 → Rev 1765

/q40ints.c
0,0 → 1,465
/*
* arch/m68k/q40/q40ints.c
*
* Copyright (C) 1999,2001 Richard Zidlicky
*
* 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.
*
* .. used to be loosely based on bvme6000ints.c
*
*/
 
#include <linux/config.h>
#include <linux/types.h>
#include <linux/kernel.h>
#include <linux/errno.h>
#include <linux/string.h>
#include <linux/sched.h>
 
#include <asm/rtc.h>
#include <asm/ptrace.h>
#include <asm/system.h>
#include <asm/irq.h>
#include <asm/hardirq.h>
#include <asm/traps.h>
 
#include <asm/q40_master.h>
#include <asm/q40ints.h>
 
/*
* Q40 IRQs are defined as follows:
* 3,4,5,6,7,10,11,14,15 : ISA dev IRQs
* 16-31: reserved
* 32 : keyboard int
* 33 : frame int (50/200 Hz periodic timer)
* 34 : sample int (10/20 KHz periodic timer)
*
*/
 
extern int ints_inited;
 
 
void q40_irq2_handler (int, void *, struct pt_regs *fp);
 
 
extern void (*q40_sys_default_handler[]) (int, void *, struct pt_regs *);
 
static void q40_defhand (int irq, void *dev_id, struct pt_regs *fp);
static void sys_default_handler(int lev, void *dev_id, struct pt_regs *regs);
 
 
#define DEVNAME_SIZE 24
 
static struct q40_irq_node {
void (*handler)(int, void *, struct pt_regs *);
unsigned long flags;
void *dev_id;
/* struct q40_irq_node *next;*/
char devname[DEVNAME_SIZE];
unsigned count;
unsigned short state;
} irq_tab[Q40_IRQ_MAX+1];
 
short unsigned q40_ablecount[Q40_IRQ_MAX+1];
 
/*
* void q40_init_IRQ (void)
*
* Parameters: None
*
* Returns: Nothing
*
* This function is called during kernel startup to initialize
* the q40 IRQ handling routines.
*/
 
static int disabled=0;
 
void q40_init_IRQ (void)
{
int i;
 
disabled=0;
for (i = 0; i <= Q40_IRQ_MAX; i++) {
irq_tab[i].handler = q40_defhand;
irq_tab[i].flags = 0;
irq_tab[i].dev_id = NULL;
/* irq_tab[i].next = NULL;*/
irq_tab[i].devname[0] = 0;
irq_tab[i].count = 0;
irq_tab[i].state =0;
q40_ablecount[i]=0; /* all enabled */
}
 
/* setup handler for ISA ints */
sys_request_irq(IRQ2,q40_irq2_handler, 0, "q40 ISA and master chip", NULL);
 
/* now enable some ints.. */
master_outb(1,EXT_ENABLE_REG); /* ISA IRQ 5-15 */
 
/* make sure keyboard IRQ is disabled */
master_outb(0,KEY_IRQ_ENABLE_REG);
}
 
int q40_request_irq(unsigned int irq,
void (*handler)(int, void *, struct pt_regs *),
unsigned long flags, const char *devname, void *dev_id)
{
/*printk("q40_request_irq %d, %s\n",irq,devname);*/
 
if (irq > Q40_IRQ_MAX || (irq>15 && irq<32)) {
printk("%s: Incorrect IRQ %d from %s\n", __FUNCTION__, irq, devname);
return -ENXIO;
}
 
/* test for ISA ints not implemented by HW */
switch (irq)
{
case 1: case 2: case 8: case 9:
case 12: case 13:
printk("%s: ISA IRQ %d from %s not implemented by HW\n", __FUNCTION__, irq, devname);
return -ENXIO;
case 11:
printk("warning IRQ 10 and 11 not distinguishable\n");
irq=10;
}
 
if (irq<Q40_IRQ_SAMPLE)
{
if (irq_tab[irq].dev_id != NULL)
{
printk("%s: IRQ %d from %s is not replaceable\n",
__FUNCTION__, irq, irq_tab[irq].devname);
return -EBUSY;
}
/*printk("IRQ %d set to handler %p\n",irq,handler);*/
if (dev_id==NULL)
{
printk("WARNING: dev_id == NULL in request_irq\n");
dev_id=(void*)1;
}
irq_tab[irq].handler = handler;
irq_tab[irq].flags = flags;
irq_tab[irq].dev_id = dev_id;
strncpy(irq_tab[irq].devname,devname,DEVNAME_SIZE);
irq_tab[irq].state = 0;
return 0;
}
else {
/* Q40_IRQ_SAMPLE :somewhat special actions required here ..*/
sys_request_irq(4,handler,flags,devname,dev_id);
sys_request_irq(6,handler,flags,devname,dev_id);
return 0;
}
}
 
void q40_free_irq(unsigned int irq, void *dev_id)
{
if (irq > Q40_IRQ_MAX || (irq>15 && irq<32)) {
printk("%s: Incorrect IRQ %d, dev_id %x \n", __FUNCTION__, irq, (unsigned)dev_id);
return;
}
 
/* test for ISA ints not implemented by HW */
switch (irq)
{
case 1: case 2: case 8: case 9:
case 12: case 13:
printk("%s: ISA IRQ %d from %x invalid\n", __FUNCTION__, irq, (unsigned)dev_id);
return;
case 11: irq=10;
}
if (irq<Q40_IRQ_SAMPLE)
{
if (irq_tab[irq].dev_id != dev_id)
printk("%s: Removing probably wrong IRQ %d from %s\n",
__FUNCTION__, irq, irq_tab[irq].devname);
irq_tab[irq].handler = q40_defhand;
irq_tab[irq].flags = 0;
irq_tab[irq].dev_id = NULL;
/* irq_tab[irq].devname = NULL; */
/* do not reset state !! */
}
else
{ /* == Q40_IRQ_SAMPLE */
sys_free_irq(4,dev_id);
sys_free_irq(6,dev_id);
}
}
 
 
void q40_process_int (int level, struct pt_regs *fp)
{
printk("unexpected interrupt vec=%x, pc=%lx, d0=%lx, d0_orig=%lx, d1=%lx, d2=%lx\n",
level, fp->pc, fp->d0, fp->orig_d0, fp->d1, fp->d2);
printk("\tIIRQ_REG = %x, EIRQ_REG = %x\n",master_inb(IIRQ_REG),master_inb(EIRQ_REG));
}
 
/*
* this stuff doesn't really belong here..
*/
 
int ql_ticks=0; /* 200Hz ticks since last jiffie */
static int sound_ticks=0;
 
#define SVOL 45
 
void q40_mksound(unsigned int hz, unsigned int ticks)
{
/* for now ignore hz, except that hz==0 switches off sound */
/* simply alternate the ampl (128-SVOL)-(128+SVOL)-..-.. at 200Hz */
if (hz==0)
{
if (sound_ticks)
sound_ticks=1;
 
*DAC_LEFT=128;
*DAC_RIGHT=128;
 
return;
}
/* sound itself is done in q40_timer_int */
if (sound_ticks == 0) sound_ticks=1000; /* pretty long beep */
sound_ticks=ticks<<1;
}
 
static void (*q40_timer_routine)(int, void *, struct pt_regs *);
 
static void q40_timer_int (int irq, void * dev, struct pt_regs * regs)
{
ql_ticks = ql_ticks ? 0 : 1;
if (sound_ticks)
{
unsigned char sval=(sound_ticks & 1) ? 128-SVOL : 128+SVOL;
sound_ticks--;
*DAC_LEFT=sval;
*DAC_RIGHT=sval;
}
 
if (ql_ticks) return;
 
q40_timer_routine(irq, dev, regs);
}
 
void q40_sched_init (void (*timer_routine)(int, void *, struct pt_regs *))
{
int timer_irq;
 
q40_timer_routine = timer_routine;
timer_irq=Q40_IRQ_FRAME;
 
if (request_irq(timer_irq, q40_timer_int, 0,
"timer", q40_timer_int))
panic ("Couldn't register timer int");
 
master_outb(-1,FRAME_CLEAR_REG);
master_outb( 1,FRAME_RATE_REG);
}
 
 
/*
* tables to translate bits into IRQ numbers
* it is a good idea to order the entries by priority
*
*/
 
struct IRQ_TABLE{ unsigned mask; int irq ;};
#if 0
static struct IRQ_TABLE iirqs[]={
{Q40_IRQ_FRAME_MASK,Q40_IRQ_FRAME},
{Q40_IRQ_KEYB_MASK,Q40_IRQ_KEYBOARD},
{0,0}};
#endif
static struct IRQ_TABLE eirqs[]={
{Q40_IRQ3_MASK,3}, /* ser 1 */
{Q40_IRQ4_MASK,4}, /* ser 2 */
{Q40_IRQ14_MASK,14}, /* IDE 1 */
{Q40_IRQ15_MASK,15}, /* IDE 2 */
{Q40_IRQ6_MASK,6}, /* floppy, handled elsewhere */
{Q40_IRQ7_MASK,7}, /* par */
 
{Q40_IRQ5_MASK,5},
{Q40_IRQ10_MASK,10},
 
 
 
 
{0,0}};
 
/* complain only this many times about spurious ints : */
static int ccleirq=60; /* ISA dev IRQ's*/
/*static int cclirq=60;*/ /* internal */
 
/* FIXME: add shared ints,mask,unmask,probing.... */
 
#define IRQ_INPROGRESS 1
/*static unsigned short saved_mask;*/
//static int do_tint=0;
 
#define DEBUG_Q40INT
/*#define IP_USE_DISABLE *//* would be nice, but crashes ???? */
 
static int mext_disabled=0; /* ext irq disabled by master chip? */
static int aliased_irq=0; /* how many times inside handler ?*/
 
 
/* got level 2 interrupt, dispatch to ISA or keyboard/timer IRQs */
void q40_irq2_handler (int vec, void *devname, struct pt_regs *fp)
{
unsigned mir, mer;
int irq,i;
 
mir=master_inb(IIRQ_REG);
if (mir&Q40_IRQ_FRAME_MASK) {
irq_tab[Q40_IRQ_FRAME].count++;
irq_tab[Q40_IRQ_FRAME].handler(Q40_IRQ_FRAME,irq_tab[Q40_IRQ_FRAME].dev_id,fp);
master_outb(-1,FRAME_CLEAR_REG);
}
if ((mir&Q40_IRQ_SER_MASK) || (mir&Q40_IRQ_EXT_MASK)) {
mer=master_inb(EIRQ_REG);
for (i=0; eirqs[i].mask; i++) {
if (mer&(eirqs[i].mask)) {
irq=eirqs[i].irq;
/*
* There is a little mess wrt which IRQ really caused this irq request. The
* main problem is that IIRQ_REG and EIRQ_REG reflect the state when they
* are read - which is long after the request came in. In theory IRQs should
* not just go away but they occassionally do
*/
if (irq>4 && irq<=15 && mext_disabled) {
/*aliased_irq++;*/
goto iirq;
}
if (irq_tab[irq].handler == q40_defhand ) {
printk("handler for IRQ %d not defined\n",irq);
continue; /* ignore uninited INTs :-( */
}
if ( irq_tab[irq].state & IRQ_INPROGRESS ) {
/* some handlers do sti() for irq latency reasons, */
/* however reentering an active irq handler is not permitted */
#ifdef IP_USE_DISABLE
/* in theory this is the better way to do it because it still */
/* lets through eg the serial irqs, unfortunately it crashes */
disable_irq(irq);
disabled=1;
#else
/*printk("IRQ_INPROGRESS detected for irq %d, disabling - %s disabled\n",irq,disabled ? "already" : "not yet"); */
fp->sr = (((fp->sr) & (~0x700))+0x200);
disabled=1;
#endif
goto iirq;
}
irq_tab[irq].count++;
irq_tab[irq].state |= IRQ_INPROGRESS;
irq_tab[irq].handler(irq,irq_tab[irq].dev_id,fp);
irq_tab[irq].state &= ~IRQ_INPROGRESS;
/* naively enable everything, if that fails than */
/* this function will be reentered immediately thus */
/* getting another chance to disable the IRQ */
if ( disabled ) {
#ifdef IP_USE_DISABLE
if (irq>4){
disabled=0;
enable_irq(irq);}
#else
disabled=0;
/*printk("reenabling irq %d\n",irq); */
#endif
}
return;
}
}
if (mer && ccleirq>0 && !aliased_irq)
printk("ISA interrupt from unknown source? EIRQ_REG = %x\n",mer),ccleirq--;
}
iirq:
mir=master_inb(IIRQ_REG);
/* should test whether keyboard irq is really enabled, doing it in defhand */
if (mir&Q40_IRQ_KEYB_MASK) {
irq_tab[Q40_IRQ_KEYBOARD].count++;
irq_tab[Q40_IRQ_KEYBOARD].handler(Q40_IRQ_KEYBOARD,irq_tab[Q40_IRQ_KEYBOARD].dev_id,fp);
}
}
 
int q40_get_irq_list (char *buf)
{
int i, len = 0;
 
for (i = 0; i <= Q40_IRQ_MAX; i++)
{
if (irq_tab[i].count)
len += sprintf (buf+len, "%sIRQ %02d: %8d %s%s\n",
(i<=15) ? "ISA-" : " " ,
i, irq_tab[i].count,
irq_tab[i].devname[0] ? irq_tab[i].devname : "?",
irq_tab[i].handler == q40_defhand ?
" (now unassigned)" : "");
}
return len;
}
 
 
static void q40_defhand (int irq, void *dev_id, struct pt_regs *fp)
{
if (irq!=Q40_IRQ_KEYBOARD)
printk ("Unknown q40 interrupt %d\n", irq);
else master_outb(-1,KEYBOARD_UNLOCK_REG);
}
static void sys_default_handler(int lev, void *dev_id, struct pt_regs *regs)
{
printk ("Uninitialised interrupt level %d\n", lev);
}
 
void (*q40_sys_default_handler[SYS_IRQS]) (int, void *, struct pt_regs *) = {
sys_default_handler,sys_default_handler,sys_default_handler,sys_default_handler,
sys_default_handler,sys_default_handler,sys_default_handler,sys_default_handler
};
 
 
void q40_enable_irq (unsigned int irq)
{
if ( irq>=5 && irq<=15 )
{
mext_disabled--;
if (mext_disabled>0)
printk("q40_enable_irq : nested disable/enable\n");
if (mext_disabled==0)
master_outb(1,EXT_ENABLE_REG);
}
}
 
 
void q40_disable_irq (unsigned int irq)
{
/* disable ISA iqs : only do something if the driver has been
* verified to be Q40 "compatible" - right now IDE, NE2K
* Any driver should not attempt to sleep across disable_irq !!
*/
 
if ( irq>=5 && irq<=15 ) {
master_outb(0,EXT_ENABLE_REG);
mext_disabled++;
if (mext_disabled>1) printk("disable_irq nesting count %d\n",mext_disabled);
}
}
 
unsigned long q40_probe_irq_on (void)
{
printk("irq probing not working - reconfigure the driver to avoid this\n");
return -1;
}
int q40_probe_irq_off (unsigned long irqs)
{
return -1;
}
/*
* Local variables:
* compile-command: "m68k-linux-gcc -D__KERNEL__ -I/home/rz/lx/linux-2.2.6/include -Wall -Wstrict-prototypes -O2 -fomit-frame-pointer -pipe -fno-strength-reduce -ffixed-a2 -m68040 -c -o q40ints.o q40ints.c"
* End:
*/
/config.c
0,0 → 1,405
/*
* arch/m68k/q40/config.c
*
* Copyright (C) 1999 Richard Zidlicky
*
* originally based on:
*
* linux/bvme/config.c
*
* This file is subject to the terms and conditions of the GNU General Public
* License. See the file README.legal in the main directory of this archive
* for more details.
*/
 
#include <linux/config.h>
#include <linux/types.h>
#include <linux/kernel.h>
#include <linux/mm.h>
#include <linux/tty.h>
#include <linux/console.h>
#include <linux/linkage.h>
#include <linux/init.h>
#include <linux/major.h>
#include <linux/serial_reg.h>
#include <linux/rtc.h>
#include <linux/vt_kern.h>
 
#include <asm/io.h>
#include <asm/rtc.h>
#include <asm/bootinfo.h>
#include <asm/system.h>
#include <asm/pgtable.h>
#include <asm/setup.h>
#include <asm/irq.h>
#include <asm/traps.h>
#include <asm/rtc.h>
#include <asm/machdep.h>
#include <asm/q40_master.h>
#include <asm/keyboard.h>
 
extern void floppy_setup(char *str, int *ints);
 
extern int q40kbd_translate(unsigned char scancode, unsigned char *keycode,
char raw_mode);
extern void q40_process_int (int level, struct pt_regs *regs);
extern void (*q40_sys_default_handler[]) (int, void *, struct pt_regs *); /* added just for debugging */
extern void q40_init_IRQ (void);
extern void q40_free_irq (unsigned int, void *);
extern int q40_get_irq_list (char *);
extern void q40_enable_irq (unsigned int);
extern void q40_disable_irq (unsigned int);
static void q40_get_model(char *model);
static int q40_get_hardware_list(char *buffer);
extern int q40_request_irq(unsigned int irq, void (*handler)(int, void *, struct pt_regs *), unsigned long flags, const char *devname, void *dev_id);
extern void q40_sched_init(void (*handler)(int, void *, struct pt_regs *));
 
extern unsigned long q40_gettimeoffset (void);
extern void q40_gettod (int *year, int *mon, int *day, int *hour,
int *min, int *sec);
extern int q40_hwclk (int, struct rtc_time *);
extern unsigned int q40_get_ss (void);
extern int q40_set_clock_mmss (unsigned long);
static int q40_get_rtc_pll(struct rtc_pll_info *pll);
static int q40_set_rtc_pll(struct rtc_pll_info *pll);
extern void q40_reset (void);
void q40_halt(void);
extern void q40_waitbut(void);
void q40_set_vectors (void);
 
void q40_mksound(unsigned int /*freq*/, unsigned int /*ticks*/ );
 
extern char *saved_command_line;
extern char m68k_debug_device[];
static void q40_mem_console_write(struct console *co, const char *b,
unsigned int count);
 
extern int ql_ticks;
 
static struct console q40_console_driver = {
name: "debug",
flags: CON_PRINTBUFFER,
index: -1,
};
 
 
/* early debugging function:*/
extern char *q40_mem_cptr; /*=(char *)0xff020000;*/
static int _cpleft;
 
#if 0
int q40_kbd_translate(unsigned char keycode, unsigned char *keycodep, char raw_mode)
{
*keycodep = keycode;
return 1;
}
#endif
 
static void q40_mem_console_write(struct console *co, const char *s,
unsigned int count)
{
char *p=(char *)s;
 
if (count<_cpleft)
while (count-- >0){
*q40_mem_cptr=*p++;
q40_mem_cptr+=4;
_cpleft--;
}
}
#if 0
void printq40(char *str)
{
int l=strlen(str);
char *p=q40_mem_cptr;
 
while (l-- >0 && _cpleft-- >0)
{
*p=*str++;
p+=4;
}
q40_mem_cptr=p;
}
#endif
 
#if 0
int q40_kbdrate (struct kbd_repeat *k)
{
return 0;
}
#endif
 
static int halted=0;
 
#ifdef CONFIG_HEARTBEAT
static void q40_heartbeat(int on)
{
if (halted) return;
 
if (on)
Q40_LED_ON();
else
Q40_LED_OFF();
}
#endif
 
void q40_reset()
{
halted=1;
printk ("\n\n*******************************************\n"
"Called q40_reset : press the RESET button!! \n"
"*******************************************\n");
Q40_LED_ON();
while(1) ;
}
void q40_halt()
{
halted=1;
printk ("\n\n*******************\n"
" Called q40_halt\n"
"*******************\n");
Q40_LED_ON();
while(1) ;
}
 
static void q40_get_model(char *model)
{
sprintf(model, "Q40");
}
 
/* No hardware options on Q40? */
 
static int q40_get_hardware_list(char *buffer)
{
*buffer = '\0';
return 0;
}
 
static unsigned int serports[]={0x3f8,0x2f8,0x3e8,0x2e8,0};
void q40_disable_irqs(void)
{
unsigned i,j;
j=0;
while((i=serports[j++])) outb(0,i+UART_IER);
master_outb(0,EXT_ENABLE_REG);
master_outb(0,KEY_IRQ_ENABLE_REG);
}
 
void __init config_q40(void)
{
mach_sched_init = q40_sched_init;
 
#ifdef CONFIG_VT
mach_keyb_init = q40kbd_init_hw;
mach_kbd_translate = q40kbd_translate;
kd_mksound = q40_mksound;
#endif
mach_init_IRQ = q40_init_IRQ;
mach_gettimeoffset = q40_gettimeoffset;
mach_gettod = q40_gettod;
mach_hwclk = q40_hwclk;
mach_get_ss = q40_get_ss;
mach_get_rtc_pll = q40_get_rtc_pll;
mach_set_rtc_pll = q40_set_rtc_pll;
mach_set_clock_mmss = q40_set_clock_mmss;
 
mach_reset = q40_reset;
mach_free_irq = q40_free_irq;
mach_process_int = q40_process_int;
mach_get_irq_list = q40_get_irq_list;
mach_request_irq = q40_request_irq;
enable_irq = q40_enable_irq;
disable_irq = q40_disable_irq;
mach_default_handler = &q40_sys_default_handler;
mach_get_model = q40_get_model;
mach_get_hardware_list = q40_get_hardware_list;
 
#ifdef CONFIG_MAGIC_SYSRQ
mach_sysrq_key = 0x54;
#endif
#ifdef CONFIG_HEARTBEAT
mach_heartbeat = q40_heartbeat;
#endif
mach_halt = q40_halt;
#ifdef CONFIG_DUMMY_CONSOLE
conswitchp = &dummy_con;
#endif
 
/* disable a few things that SMSQ might have left enabled */
q40_disable_irqs();
 
/* no DMA at all, but ide-scsi requires it.. make sure
* all physical RAM fits into the boundary - otherwise
* allocator may play costly and useless tricks */
mach_max_dma_address = 1024*1024*1024;
 
/* useful for early debugging stages - writes kernel messages into SRAM */
if (!strncmp( m68k_debug_device,"mem",3 ))
{
/*printk("using NVRAM debug, q40_mem_cptr=%p\n",q40_mem_cptr);*/
_cpleft=2000-((long)q40_mem_cptr-0xff020000)/4;
q40_console_driver.write = q40_mem_console_write;
register_console(&q40_console_driver);
}
}
 
 
int q40_parse_bootinfo(const struct bi_record *rec)
{
return 1;
}
 
 
static inline unsigned char bcd2bin (unsigned char b)
{
return ((b>>4)*10 + (b&15));
}
 
static inline unsigned char bin2bcd (unsigned char b)
{
return (((b/10)*16) + (b%10));
}
 
 
unsigned long q40_gettimeoffset (void)
{
return 5000*(ql_ticks!=0);
}
 
extern void q40_gettod (int *year, int *mon, int *day, int *hour,
int *min, int *sec)
{
Q40_RTC_CTRL |= Q40_RTC_READ;
*year = bcd2bin (Q40_RTC_YEAR);
*mon = bcd2bin (Q40_RTC_MNTH);
*day = bcd2bin (Q40_RTC_DATE);
*hour = bcd2bin (Q40_RTC_HOUR);
*min = bcd2bin (Q40_RTC_MINS);
*sec = bcd2bin (Q40_RTC_SECS);
Q40_RTC_CTRL &= ~(Q40_RTC_READ);
 
}
 
 
 
/*
* Looks like op is non-zero for setting the clock, and zero for
* reading the clock.
*
* struct hwclk_time {
* unsigned sec; 0..59
* unsigned min; 0..59
* unsigned hour; 0..23
* unsigned day; 1..31
* unsigned mon; 0..11
* unsigned year; 00...
* int wday; 0..6, 0 is Sunday, -1 means unknown/don't set
* };
*/
 
int q40_hwclk(int op, struct rtc_time *t)
{
if (op)
{ /* Write.... */
Q40_RTC_CTRL |= Q40_RTC_WRITE;
 
Q40_RTC_SECS = bin2bcd(t->tm_sec);
Q40_RTC_MINS = bin2bcd(t->tm_min);
Q40_RTC_HOUR = bin2bcd(t->tm_hour);
Q40_RTC_DATE = bin2bcd(t->tm_mday);
Q40_RTC_MNTH = bin2bcd(t->tm_mon + 1);
Q40_RTC_YEAR = bin2bcd(t->tm_year%100);
if (t->tm_wday >= 0)
Q40_RTC_DOW = bin2bcd(t->tm_wday+1);
 
Q40_RTC_CTRL &= ~(Q40_RTC_WRITE);
}
else
{ /* Read.... */
Q40_RTC_CTRL |= Q40_RTC_READ;
 
t->tm_year = bcd2bin (Q40_RTC_YEAR);
t->tm_mon = bcd2bin (Q40_RTC_MNTH)-1;
t->tm_mday = bcd2bin (Q40_RTC_DATE);
t->tm_hour = bcd2bin (Q40_RTC_HOUR);
t->tm_min = bcd2bin (Q40_RTC_MINS);
t->tm_sec = bcd2bin (Q40_RTC_SECS);
 
Q40_RTC_CTRL &= ~(Q40_RTC_READ);
if (t->tm_year < 70)
t->tm_year += 100;
t->tm_wday = bcd2bin(Q40_RTC_DOW)-1;
 
}
 
return 0;
}
 
unsigned int q40_get_ss()
{
return bcd2bin(Q40_RTC_SECS);
}
 
/*
* Set the minutes and seconds from seconds value 'nowtime'. Fail if
* clock is out by > 30 minutes. Logic lifted from atari code.
*/
 
int q40_set_clock_mmss (unsigned long nowtime)
{
int retval = 0;
short real_seconds = nowtime % 60, real_minutes = (nowtime / 60) % 60;
 
int rtc_minutes;
 
 
rtc_minutes = bcd2bin (Q40_RTC_MINS);
 
if ((rtc_minutes < real_minutes
? real_minutes - rtc_minutes
: rtc_minutes - real_minutes) < 30)
{
Q40_RTC_CTRL |= Q40_RTC_WRITE;
Q40_RTC_MINS = bin2bcd(real_minutes);
Q40_RTC_SECS = bin2bcd(real_seconds);
Q40_RTC_CTRL &= ~(Q40_RTC_WRITE);
}
else
retval = -1;
 
 
return retval;
}
 
 
/* get and set PLL calibration of RTC clock */
#define Q40_RTC_PLL_MASK ((1<<5)-1)
#define Q40_RTC_PLL_SIGN (1<<5)
 
static int q40_get_rtc_pll(struct rtc_pll_info *pll)
{
int tmp=Q40_RTC_CTRL;
pll->pll_value = tmp & Q40_RTC_PLL_MASK;
if (tmp & Q40_RTC_PLL_SIGN)
pll->pll_value = -pll->pll_value;
pll->pll_max=31;
pll->pll_min=-31;
pll->pll_posmult=512;
pll->pll_negmult=256;
pll->pll_clock=125829120;
return 0;
}
 
static int q40_set_rtc_pll(struct rtc_pll_info *pll)
{
if (!pll->pll_ctrl){
/* the docs are a bit unclear so I am doublesetting RTC_WRITE here ... */
int tmp=(pll->pll_value & 31) | (pll->pll_value<0 ? 32 : 0) | Q40_RTC_WRITE;
Q40_RTC_CTRL |= Q40_RTC_WRITE;
Q40_RTC_CTRL = tmp;
Q40_RTC_CTRL &= ~(Q40_RTC_WRITE);
return 0;
} else return -EINVAL;
}
/Makefile
0,0 → 1,14
#
# Makefile for Linux arch/m68k/q40 source directory
#
# Note! Dependencies are done automagically by 'make dep', which also
# removes any old dependencies. DON'T put your own dependencies here
# unless it's something special (ie not a .c file).
#
# Note 2! The CFLAGS definitions are now in the main makefile...
 
O_TARGET := q40.o
 
obj-y := config.o q40ints.o
 
include $(TOPDIR)/Rules.make
/README
0,0 → 1,138
Linux for the Q40
=================
 
You may try http://www.geocities.com/SiliconValley/Bay/2602/ for
some up to date information. Booter and other tools will be also
available from this place or ftp.uni-erlangen.de/linux/680x0/q40/
and mirrors.
 
Hints to documentation usually refer to the linux source tree in
/usr/src/linux/Documentation unless URL given.
 
It seems IRQ unmasking can't be safely done on a Q40. IRQ probing
is not implemented - do not try it! (See below)
 
For a list of kernel command-line options read the documentation for the
particular device drivers.
 
The floppy imposes a very high interrupt load on the CPU, approx 30K/s.
When something blocks interrupts (HD) it will loose some of them, so far
this is not known to have caused any data loss. On highly loaded systems
it can make the floppy very slow or practically stop. Other Q40 OS' simply
poll the floppy for this reason - something that can't be done in Linux.
Only possible cure is getting a 82072 controller with fifo instead of
the 8272A.
 
drivers used by the Q40, apart from the very obvious (console etc.):
drivers/char/q40_keyb.c # use PC keymaps for national keyboards
serial.c # normal PC driver - any speed
lp.c # printer driver
genrtc.c # RTC
char/joystick/* # most of this should work, not
# in default config.in
block/q40ide.c # startup for ide
ide* # see Documentation/ide.txt
floppy.c # normal PC driver, DMA emu in asm/floppy.h
# and arch/m68k/kernel/entry.S
# see drivers/block/README.fd
net/ne.c
video/q40fb.c
parport/*
sound/dmasound_core.c
dmasound_q40.c
 
Various other PC drivers can be enabled simply by adding them to
arch/m68k/config.in, especially 8 bit devices should be without any
problems. For cards using 16bit io/mem more care is required, like
checking byte order issues, hacking memcpy_*_io etc.
 
 
Debugging
=========
 
Upon startup the kernel will usually output "ABCQGHIJ" into the SRAM,
preceded by the booter signature. This is a trace just in case something
went wrong during earliest setup stages of head.S.
**Changed** to preserve SRAM contents by default, this is only done when
requested - SRAM must start with '%LX$' signature to do this. '-d' option
to 'lxx' loader enables this.
 
SRAM can also be used as additional console device, use debug=mem.
This will save kernel startup msgs into SRAM, the screen will display
only the penguin - and shell prompt if it gets that far..
Unfortunately only 2000 bytes are available.
 
Serial console works and can also be used for debugging, see loader_txt
 
Most problems seem to be caused by fawlty or badly configured io-cards or
hard drives anyway.
Make sure to configure the parallel port as SPP and remove IRQ/DMA jumpers
for first testing. The Q40 does not support DMA and may have trouble with
parallel ports version of interrupts.
 
 
Q40 Hardware Description
========================
 
This is just an overview, see asm-m68k/* for details ask if you have any
questions.
 
The Q40 consists of a 68040@40 MHz, 1MB video RAM, up to 32MB RAM, AT-style
keyboard interface, 1 Programmable LED, 2x8bit DACs and up to 1MB ROM, 1MB
shadow ROM.
The Q60 has any of 68060 or 68LC060 and up to 128 MB RAM.
 
Most interfacing like floppy, IDE, serial and parallel ports is done via ISA
slots. The ISA io and mem range is mapped (sparse&byteswapped!) into separate
regions of the memory.
The main interrupt register IIRQ_REG will indicate whether an IRQ was internal
or from some ISA devices, EIRQ_REG can distinguish up to 8 ISA IRQs.
 
The Q40 custom chip is programmable to provide 2 periodic timers:
- 50 or 200 Hz - level 2, !!THIS CANT BE DISABLED!!
- 10 or 20 KHz - level 4, used for dma-sound
Linux uses the 200 Hz interrupt for timer and beep by default.
 
 
Interrupts
==========
 
q40 master chip handles only a subset of level triggered interrupts.
 
Linux has some requirements wrt interrupt architecture, these are
to my knowledge:
(a) interrupt handler must not be reentered even when sti() is called
from within handler
(b) working enable/disable_irq
 
Luckily these requirements are only important for drivers shared
with other architectures - ide,serial,parallel, ethernet.
q40ints.c now contains a trivial hack for (a), (b) is more difficult
because only irq's 4-15 can be disabled - and only all of them at once.
Thus disable_irq() can effectively block the machine if the driver goes
asleep.
One thing to keep in mind when hacking around the interrupt code is
that there is no way to find out which IRQ caused a request, [EI]IRQ_REG
displays current state of the various IRQ lines.
 
Keyboard
========
 
q40 receives AT make/break codes from the keyboard, these are translated to
the PC scancodes x86 Linux uses. So by theory every national keyboard should
work just by loading the appropriate x86 keytable - see any national-HOWTO.
 
Unfortunately the AT->PC translation isn't quite trivial and even worse, my
documentation of it is absolutely minimal - thus some exotic keys may not
behave exactly as expected.
 
There is still hope that it can be fixed completely though. If you encounter
problems, email me ideally this:
- exact keypress/release sequence
- 'showkey -s' run on q40, non-X session
- 'showkey -s' run on a PC, non-X session
- AT codes as displayed by the q40 debugging ROM
btw if the showkey output from PC and Q40 doesn't differ then you have some
classic configuration problem - don't send me anything in this case
 

powered by: WebSVN 2.1.0

© copyright 1999-2024 OpenCores.org, equivalent to Oliscience, all rights reserved. OpenCores®, registered trademark.