linux-bk/arch/ppc/platforms/apus_setup.c
<<
>>
Prefs
   1/*
   2 * BK Id: %F% %I% %G% %U% %#%
   3 */
   4/*
   5 *  arch/ppc/platforms/apus_setup.c
   6 *
   7 *  Copyright (C) 1998, 1999  Jesper Skov
   8 *
   9 *  Basically what is needed to replace functionality found in
  10 *  arch/m68k allowing Amiga drivers to work under APUS.
  11 *  Bits of code and/or ideas from arch/m68k and arch/ppc files.
  12 *
  13 * TODO:
  14 *  This file needs a *really* good cleanup. Restructure and optimize.
  15 *  Make sure it can be compiled for non-APUS configs. Begin to move
  16 *  Amiga specific stuff into mach/amiga.
  17 */
  18
  19#include <linux/config.h>
  20#include <linux/kernel.h>
  21#include <linux/sched.h>
  22#include <linux/init.h>
  23#include <linux/blk.h>
  24#include <linux/seq_file.h>
  25
  26/* Needs INITSERIAL call in head.S! */
  27#undef APUS_DEBUG
  28
  29#include <asm/bootinfo.h>
  30#include <asm/setup.h>
  31#include <asm/amigahw.h>
  32#include <asm/amigaints.h>
  33#include <asm/amigappc.h>
  34#include <asm/pgtable.h>
  35#include <asm/dma.h>
  36#include <asm/machdep.h>
  37#include <asm/keyboard.h>
  38#include <asm/time.h>
  39
  40unsigned long m68k_machtype;
  41char debug_device[6] = "";
  42
  43extern void amiga_init_IRQ(void);
  44
  45extern int amiga_kbd_translate(unsigned char keycode, unsigned char *keycodep, char raw_mode);
  46extern char amiga_sysrq_xlate[128];
  47
  48extern void apus_setup_pci_ptrs(void);
  49
  50void (*mach_sched_init) (void (*handler)(int, void *, struct pt_regs *)) __initdata = NULL;
  51/* machine dependent keyboard functions */
  52int (*mach_keyb_init) (void) __initdata = NULL;
  53int (*mach_kbdrate) (struct kbd_repeat *) = NULL;
  54void (*mach_kbd_leds) (unsigned int) = NULL;
  55/* machine dependent irq functions */
  56void (*mach_init_IRQ) (void) __initdata = NULL;
  57void (*(*mach_default_handler)[]) (int, void *, struct pt_regs *) = NULL;
  58void (*mach_get_model) (char *model) = NULL;
  59int (*mach_get_hardware_list) (char *buffer) = NULL;
  60int (*mach_get_irq_list) (struct seq_file *, void *) = NULL;
  61void (*mach_process_int) (int, struct pt_regs *) = NULL;
  62/* machine dependent timer functions */
  63unsigned long (*mach_gettimeoffset) (void);
  64void (*mach_gettod) (int*, int*, int*, int*, int*, int*);
  65int (*mach_hwclk) (int, struct hwclk_time*) = NULL;
  66int (*mach_set_clock_mmss) (unsigned long) = NULL;
  67void (*mach_reset)( void );
  68long mach_max_dma_address = 0x00ffffff; /* default set to the lower 16MB */
  69#if defined(CONFIG_AMIGA_FLOPPY)
  70void (*mach_floppy_setup) (char *, int *) __initdata = NULL;
  71#endif
  72#ifdef CONFIG_HEARTBEAT
  73void (*mach_heartbeat) (int) = NULL;
  74extern void apus_heartbeat (void);
  75#endif
  76
  77extern unsigned long amiga_model;
  78extern unsigned decrementer_count;/* count value for 1e6/HZ microseconds */
  79extern unsigned count_period_num; /* 1 decrementer count equals */
  80extern unsigned count_period_den; /* count_period_num / count_period_den us */
  81
  82int num_memory = 0;
  83struct mem_info memory[NUM_MEMINFO];/* memory description */
  84/* FIXME: Duplicate memory data to avoid conflicts with m68k shared code. */
  85int m68k_realnum_memory = 0;
  86struct mem_info m68k_memory[NUM_MEMINFO];/* memory description */
  87
  88struct mem_info ramdisk;
  89
  90extern void amiga_floppy_setup(char *, int *);
  91extern void config_amiga(void);
  92
  93static int __60nsram = 0;
  94
  95/* for cpuinfo */
  96static int __bus_speed = 0;
  97static int __speed_test_failed = 0;
  98
  99/********************************************** COMPILE PROTECTION */
 100/* Provide some stubs that links to Amiga specific functions.
 101 * This allows CONFIG_APUS to be removed from generic PPC files while
 102 * preventing link errors for other PPC targets.
 103 */
 104unsigned long apus_get_rtc_time(void)
 105{
 106#ifdef CONFIG_APUS
 107        extern unsigned long m68k_get_rtc_time(void);
 108
 109        return m68k_get_rtc_time ();
 110#else
 111        return 0;
 112#endif
 113}
 114
 115int apus_set_rtc_time(unsigned long nowtime)
 116{
 117#ifdef CONFIG_APUS
 118        extern int m68k_set_rtc_time(unsigned long nowtime);
 119
 120        return m68k_set_rtc_time (nowtime);
 121#else
 122        return 0;
 123#endif
 124}
 125
 126/*********************************************************** SETUP */
 127/* From arch/m68k/kernel/setup.c. */
 128void __init apus_setup_arch(void)
 129{
 130#ifdef CONFIG_APUS
 131        extern char cmd_line[];
 132        int i;
 133        char *p, *q;
 134
 135        /* Let m68k-shared code know it should do the Amiga thing. */
 136        m68k_machtype = MACH_AMIGA;
 137
 138        /* Parse the command line for arch-specific options.
 139         * For the m68k, this is currently only "debug=xxx" to enable printing
 140         * certain kernel messages to some machine-specific device.  */
 141        for( p = cmd_line; p && *p; ) {
 142            i = 0;
 143            if (!strncmp( p, "debug=", 6 )) {
 144                    strncpy( debug_device, p+6, sizeof(debug_device)-1 );
 145                    debug_device[sizeof(debug_device)-1] = 0;
 146                    if ((q = strchr( debug_device, ' ' ))) *q = 0;
 147                    i = 1;
 148            } else if (!strncmp( p, "60nsram", 7 )) {
 149                    APUS_WRITE (APUS_REG_WAITSTATE,
 150                                REGWAITSTATE_SETRESET
 151                                |REGWAITSTATE_PPCR
 152                                |REGWAITSTATE_PPCW);
 153                    __60nsram = 1;
 154                    i = 1;
 155            }
 156
 157            if (i) {
 158                /* option processed, delete it */
 159                if ((q = strchr( p, ' ' )))
 160                    strcpy( p, q+1 );
 161                else
 162                    *p = 0;
 163            } else {
 164                if ((p = strchr( p, ' ' ))) ++p;
 165            }
 166        }
 167
 168        config_amiga();
 169
 170#if 0 /* Enable for logging - also include logging.o in Makefile rule */
 171        {
 172#define LOG_SIZE 4096
 173                void* base;
 174
 175                /* Throw away some memory - the P5 firmare stomps on top
 176                 * of CHIP memory during bootup.
 177                 */
 178                amiga_chip_alloc(0x1000);
 179
 180                base = amiga_chip_alloc(LOG_SIZE+sizeof(klog_data_t));
 181                LOG_INIT(base, base+sizeof(klog_data_t), LOG_SIZE);
 182        }
 183#endif
 184#endif
 185}
 186
 187int
 188apus_show_cpuinfo(struct seq_file *m)
 189{
 190        extern int __map_without_bats;
 191        extern unsigned long powerup_PCI_present;
 192
 193        seq_printf(m, "machine\t\t: Amiga\n");
 194        seq_printf(m, "bus speed\t: %d%s", __bus_speed,
 195                   (__speed_test_failed) ? " [failed]\n" : "\n");
 196        seq_printf(m, "using BATs\t: %s\n",
 197                   (__map_without_bats) ? "No" : "Yes");
 198        seq_printf(m, "ram speed\t: %dns\n", (__60nsram) ? 60 : 70);
 199        seq_printf(m, "PCI bridge\t: %s\n",
 200                   (powerup_PCI_present) ? "Yes" : "No");
 201        return 0;
 202}
 203
 204static void get_current_tb(unsigned long long *time)
 205{
 206        __asm __volatile ("1:mftbu 4      \n\t"
 207                          "  mftb  5      \n\t"
 208                          "  mftbu 6      \n\t"
 209                          "  cmpw  4,6    \n\t"
 210                          "  bne   1b     \n\t"
 211                          "  stw   4,0(%0)\n\t"
 212                          "  stw   5,4(%0)\n\t"
 213                          :
 214                          : "r" (time)
 215                          : "r4", "r5", "r6");
 216}
 217
 218
 219void apus_calibrate_decr(void)
 220{
 221#ifdef CONFIG_APUS
 222        unsigned long freq;
 223
 224        /* This algorithm for determining the bus speed was
 225           contributed by Ralph Schmidt. */
 226        unsigned long long start, stop;
 227        int bus_speed;
 228        int speed_test_failed = 0;
 229
 230        {
 231                unsigned long loop = amiga_eclock / 10;
 232
 233                get_current_tb (&start);
 234                while (loop--) {
 235                        unsigned char tmp;
 236
 237                        tmp = ciaa.pra;
 238                }
 239                get_current_tb (&stop);
 240        }
 241
 242        bus_speed = (((unsigned long)(stop-start))*10*4) / 1000000;
 243        if (AMI_1200 == amiga_model)
 244                bus_speed /= 2;
 245
 246        if ((bus_speed >= 47) && (bus_speed < 53)) {
 247                bus_speed = 50;
 248                freq = 12500000;
 249        } else if ((bus_speed >= 57) && (bus_speed < 63)) {
 250                bus_speed = 60;
 251                freq = 15000000;
 252        } else if ((bus_speed >= 63) && (bus_speed < 69)) {
 253                bus_speed = 67;
 254                freq = 16666667;
 255        } else {
 256                printk ("APUS: Unable to determine bus speed (%d). "
 257                        "Defaulting to 50MHz", bus_speed);
 258                bus_speed = 50;
 259                freq = 12500000;
 260                speed_test_failed = 1;
 261        }
 262
 263        /* Ease diagnostics... */
 264        {
 265                extern int __map_without_bats;
 266                extern unsigned long powerup_PCI_present;
 267
 268                printk ("APUS: BATs=%d, BUS=%dMHz",
 269                        (__map_without_bats) ? 0 : 1,
 270                        bus_speed);
 271                if (speed_test_failed)
 272                        printk ("[FAILED - please report]");
 273
 274                printk (", RAM=%dns, PCI bridge=%d\n",
 275                        (__60nsram) ? 60 : 70,
 276                        (powerup_PCI_present) ? 1 : 0);
 277
 278                /* print a bit more if asked politely... */
 279                if (!(ciaa.pra & 0x40)){
 280                        extern unsigned int bat_addrs[4][3];
 281                        int b;
 282                        for (b = 0; b < 4; ++b) {
 283                                printk ("APUS: BAT%d ", b);
 284                                printk ("%08x-%08x -> %08x\n",
 285                                        bat_addrs[b][0],
 286                                        bat_addrs[b][1],
 287                                        bat_addrs[b][2]);
 288                        }
 289                }
 290
 291        }
 292
 293        printk("time_init: decrementer frequency = %lu.%.6lu MHz\n",
 294               freq/1000000, freq%1000000);
 295        tb_ticks_per_jiffy = freq / HZ;
 296        tb_to_us = mulhwu_scale_factor(freq, 1000000);
 297
 298        __bus_speed = bus_speed;
 299        __speed_test_failed = speed_test_failed;
 300#endif
 301}
 302
 303void arch_gettod(int *year, int *mon, int *day, int *hour,
 304                 int *min, int *sec)
 305{
 306#ifdef CONFIG_APUS
 307        if (mach_gettod)
 308                mach_gettod(year, mon, day, hour, min, sec);
 309        else
 310                *year = *mon = *day = *hour = *min = *sec = 0;
 311#endif
 312}
 313
 314/* for "kbd-reset" cmdline param */
 315__init
 316void kbd_reset_setup(char *str, int *ints)
 317{
 318}
 319
 320/*********************************************************** FLOPPY */
 321#if defined(CONFIG_AMIGA_FLOPPY)
 322__init
 323void floppy_setup(char *str, int *ints)
 324{
 325        if (mach_floppy_setup)
 326                mach_floppy_setup (str, ints);
 327}
 328#endif
 329
 330/*********************************************************** MEMORY */
 331#define KMAP_MAX 32
 332unsigned long kmap_chunks[KMAP_MAX*3];
 333int kmap_chunk_count = 0;
 334
 335/* From pgtable.h */
 336static __inline__ pte_t *my_find_pte(struct mm_struct *mm,unsigned long va)
 337{
 338        pgd_t *dir = 0;
 339        pmd_t *pmd = 0;
 340        pte_t *pte = 0;
 341
 342        va &= PAGE_MASK;
 343
 344        dir = pgd_offset( mm, va );
 345        if (dir)
 346        {
 347                pmd = pmd_offset(dir, va & PAGE_MASK);
 348                if (pmd && pmd_present(*pmd))
 349                {
 350                        pte = pte_offset(pmd, va);
 351                }
 352        }
 353        return pte;
 354}
 355
 356
 357/* Again simulating an m68k/mm/kmap.c function. */
 358void kernel_set_cachemode( unsigned long address, unsigned long size,
 359                           unsigned int cmode )
 360{
 361        unsigned long mask, flags;
 362
 363        switch (cmode)
 364        {
 365        case IOMAP_FULL_CACHING:
 366                mask = ~(_PAGE_NO_CACHE | _PAGE_GUARDED);
 367                flags = 0;
 368                break;
 369        case IOMAP_NOCACHE_SER:
 370                mask = ~0;
 371                flags = (_PAGE_NO_CACHE | _PAGE_GUARDED);
 372                break;
 373        default:
 374                panic ("kernel_set_cachemode() doesn't support mode %d\n",
 375                       cmode);
 376                break;
 377        }
 378
 379        size /= PAGE_SIZE;
 380        address &= PAGE_MASK;
 381        while (size--)
 382        {
 383                pte_t *pte;
 384
 385                pte = my_find_pte(&init_mm, address);
 386                if ( !pte )
 387                {
 388                        printk("pte NULL in kernel_set_cachemode()\n");
 389                        return;
 390                }
 391
 392                pte_val (*pte) &= mask;
 393                pte_val (*pte) |= flags;
 394                flush_tlb_page(find_vma(&init_mm,address),address);
 395
 396                address += PAGE_SIZE;
 397        }
 398}
 399
 400unsigned long mm_ptov (unsigned long paddr)
 401{
 402        unsigned long ret;
 403        if (paddr < 16*1024*1024)
 404                ret = ZTWO_VADDR(paddr);
 405        else {
 406                int i;
 407
 408                for (i = 0; i < kmap_chunk_count;){
 409                        unsigned long phys = kmap_chunks[i++];
 410                        unsigned long size = kmap_chunks[i++];
 411                        unsigned long virt = kmap_chunks[i++];
 412                        if (paddr >= phys
 413                            && paddr < (phys + size)){
 414                                ret = virt + paddr - phys;
 415                                goto exit;
 416                        }
 417                }
 418
 419                ret = (unsigned long) __va(paddr);
 420        }
 421exit:
 422#ifdef DEBUGPV
 423        printk ("PTOV(%lx)=%lx\n", paddr, ret);
 424#endif
 425        return ret;
 426}
 427
 428int mm_end_of_chunk (unsigned long addr, int len)
 429{
 430        if (memory[0].addr + memory[0].size == addr + len)
 431                return 1;
 432        return 0;
 433}
 434
 435/*********************************************************** CACHE */
 436
 437#define L1_CACHE_BYTES 32
 438#define MAX_CACHE_SIZE 8192
 439void cache_push(__u32 addr, int length)
 440{
 441        addr = mm_ptov(addr);
 442
 443        if (MAX_CACHE_SIZE < length)
 444                length = MAX_CACHE_SIZE;
 445
 446        while(length > 0){
 447                __asm ("dcbf 0,%0\n\t"
 448                       : : "r" (addr));
 449                addr += L1_CACHE_BYTES;
 450                length -= L1_CACHE_BYTES;
 451        }
 452        /* Also flush trailing block */
 453        __asm ("dcbf 0,%0\n\t"
 454               "sync \n\t"
 455               : : "r" (addr));
 456}
 457
 458void cache_clear(__u32 addr, int length)
 459{
 460        if (MAX_CACHE_SIZE < length)
 461                length = MAX_CACHE_SIZE;
 462
 463        addr = mm_ptov(addr);
 464
 465        __asm ("dcbf 0,%0\n\t"
 466               "sync \n\t"
 467               "icbi 0,%0 \n\t"
 468               "isync \n\t"
 469               : : "r" (addr));
 470
 471        addr += L1_CACHE_BYTES;
 472        length -= L1_CACHE_BYTES;
 473
 474        while(length > 0){
 475                __asm ("dcbf 0,%0\n\t"
 476                       "sync \n\t"
 477                       "icbi 0,%0 \n\t"
 478                       "isync \n\t"
 479                       : : "r" (addr));
 480                addr += L1_CACHE_BYTES;
 481                length -= L1_CACHE_BYTES;
 482        }
 483
 484        __asm ("dcbf 0,%0\n\t"
 485               "sync \n\t"
 486               "icbi 0,%0 \n\t"
 487               "isync \n\t"
 488               : : "r" (addr));
 489}
 490
 491/****************************************************** from setup.c */
 492void
 493apus_restart(char *cmd)
 494{
 495        cli();
 496
 497        APUS_WRITE(APUS_REG_LOCK,
 498                   REGLOCK_BLACKMAGICK1|REGLOCK_BLACKMAGICK2);
 499        APUS_WRITE(APUS_REG_LOCK,
 500                   REGLOCK_BLACKMAGICK1|REGLOCK_BLACKMAGICK3);
 501        APUS_WRITE(APUS_REG_LOCK,
 502                   REGLOCK_BLACKMAGICK2|REGLOCK_BLACKMAGICK3);
 503        APUS_WRITE(APUS_REG_SHADOW, REGSHADOW_SELFRESET);
 504        APUS_WRITE(APUS_REG_RESET, REGRESET_AMIGARESET);
 505        for(;;);
 506}
 507
 508void
 509apus_power_off(void)
 510{
 511        for (;;);
 512}
 513
 514void
 515apus_halt(void)
 516{
 517   apus_restart(NULL);
 518}
 519
 520/****************************************************** IRQ stuff */
 521
 522static unsigned char last_ipl[8];
 523
 524int apus_get_irq(struct pt_regs* regs)
 525{
 526        unsigned char ipl_emu, mask;
 527        unsigned int level;
 528
 529        APUS_READ(APUS_IPL_EMU, ipl_emu);
 530        level = (ipl_emu >> 3) & IPLEMU_IPLMASK;
 531        mask = IPLEMU_SETRESET|IPLEMU_DISABLEINT|level;
 532        level ^= 7;
 533
 534        /* Save previous IPL value */
 535        if (last_ipl[level])
 536                return -2;
 537        last_ipl[level] = ipl_emu;
 538
 539        /* Set to current IPL value */
 540        APUS_WRITE(APUS_IPL_EMU, mask);
 541        APUS_WRITE(APUS_IPL_EMU, IPLEMU_DISABLEINT|level);
 542
 543
 544#ifdef __INTERRUPT_DEBUG
 545        printk("<%d:%d>", level, ~ipl_emu & IPLEMU_IPLMASK);
 546#endif
 547        return level + IRQ_AMIGA_AUTO;
 548}
 549
 550void apus_end_irq(unsigned int irq)
 551{
 552        unsigned char ipl_emu;
 553        unsigned int level = irq - IRQ_AMIGA_AUTO;
 554#ifdef __INTERRUPT_DEBUG
 555        printk("{%d}", ~last_ipl[level] & IPLEMU_IPLMASK);
 556#endif
 557        /* Restore IPL to the previous value */
 558        ipl_emu = last_ipl[level] & IPLEMU_IPLMASK;
 559        APUS_WRITE(APUS_IPL_EMU, IPLEMU_SETRESET|IPLEMU_DISABLEINT|ipl_emu);
 560        last_ipl[level] = 0;
 561        ipl_emu ^= 7;
 562        APUS_WRITE(APUS_IPL_EMU, IPLEMU_DISABLEINT|ipl_emu);
 563}
 564
 565/****************************************************** keyboard */
 566static int apus_kbd_setkeycode(unsigned int scancode, unsigned int keycode)
 567{
 568        return -EOPNOTSUPP;
 569}
 570
 571static int apus_kbd_getkeycode(unsigned int scancode)
 572{
 573        return scancode > 127 ? -EINVAL : scancode;
 574}
 575
 576static char apus_kbd_unexpected_up(unsigned char keycode)
 577{
 578        return 0200;
 579}
 580
 581static void apus_kbd_init_hw(void)
 582{
 583#ifdef CONFIG_APUS
 584        extern int amiga_keyb_init(void);
 585
 586        amiga_keyb_init();
 587#endif
 588}
 589
 590
 591/****************************************************** debugging */
 592
 593/* some serial hardware definitions */
 594#define SDR_OVRUN   (1<<15)
 595#define SDR_RBF     (1<<14)
 596#define SDR_TBE     (1<<13)
 597#define SDR_TSRE    (1<<12)
 598
 599#define AC_SETCLR   (1<<15)
 600#define AC_UARTBRK  (1<<11)
 601
 602#define SER_DTR     (1<<7)
 603#define SER_RTS     (1<<6)
 604#define SER_DCD     (1<<5)
 605#define SER_CTS     (1<<4)
 606#define SER_DSR     (1<<3)
 607
 608static __inline__ void ser_RTSon(void)
 609{
 610    ciab.pra &= ~SER_RTS; /* active low */
 611}
 612
 613int __debug_ser_out( unsigned char c )
 614{
 615        custom.serdat = c | 0x100;
 616        mb();
 617        while (!(custom.serdatr & 0x2000))
 618                barrier();
 619        return 1;
 620}
 621
 622unsigned char __debug_ser_in( void )
 623{
 624        unsigned char c;
 625
 626        /* XXX: is that ok?? derived from amiga_ser.c... */
 627        while( !(custom.intreqr & IF_RBF) )
 628                barrier();
 629        c = custom.serdatr;
 630        /* clear the interrupt, so that another character can be read */
 631        custom.intreq = IF_RBF;
 632        return c;
 633}
 634
 635int __debug_serinit( void )
 636{
 637        unsigned long flags;
 638
 639        save_flags (flags);
 640        cli();
 641
 642        /* turn off Rx and Tx interrupts */
 643        custom.intena = IF_RBF | IF_TBE;
 644
 645        /* clear any pending interrupt */
 646        custom.intreq = IF_RBF | IF_TBE;
 647
 648        restore_flags (flags);
 649
 650        /*
 651         * set the appropriate directions for the modem control flags,
 652         * and clear RTS and DTR
 653         */
 654        ciab.ddra |= (SER_DTR | SER_RTS);   /* outputs */
 655        ciab.ddra &= ~(SER_DCD | SER_CTS | SER_DSR);  /* inputs */
 656
 657#ifdef CONFIG_KGDB
 658        /* turn Rx interrupts on for GDB */
 659        custom.intena = IF_SETCLR | IF_RBF;
 660        ser_RTSon();
 661#endif
 662
 663        return 0;
 664}
 665
 666void __debug_print_hex(unsigned long x)
 667{
 668        int i;
 669        char hexchars[] = "0123456789ABCDEF";
 670
 671        for (i = 0; i < 8; i++) {
 672                __debug_ser_out(hexchars[(x >> 28) & 15]);
 673                x <<= 4;
 674        }
 675        __debug_ser_out('\n');
 676        __debug_ser_out('\r');
 677}
 678
 679void __debug_print_string(char* s)
 680{
 681        unsigned char c;
 682        while((c = *s++))
 683                __debug_ser_out(c);
 684        __debug_ser_out('\n');
 685        __debug_ser_out('\r');
 686}
 687
 688static void apus_progress(char *s, unsigned short value)
 689{
 690        __debug_print_string(s);
 691}
 692
 693/****************************************************** init */
 694
 695/* The number of spurious interrupts */
 696volatile unsigned int num_spurious;
 697
 698extern struct irqaction amiga_sys_irqaction[AUTO_IRQS];
 699
 700
 701extern void amiga_enable_irq(unsigned int irq);
 702extern void amiga_disable_irq(unsigned int irq);
 703
 704struct hw_interrupt_type amiga_sys_irqctrl = {
 705        typename: "Amiga IPL",
 706        end: apus_end_irq,
 707};
 708
 709struct hw_interrupt_type amiga_irqctrl = {
 710        typename: "Amiga    ",
 711        enable: amiga_enable_irq,
 712        disable: amiga_disable_irq,
 713};
 714
 715#define HARDWARE_MAPPED_SIZE (512*1024)
 716unsigned long __init apus_find_end_of_memory(void)
 717{
 718        int shadow = 0;
 719        unsigned long total;
 720
 721        /* The memory size reported by ADOS excludes the 512KB
 722           reserved for PPC exception registers and possibly 512KB
 723           containing a shadow of the ADOS ROM. */
 724        {
 725                unsigned long size = memory[0].size;
 726
 727                /* If 2MB aligned, size was probably user
 728                   specified. We can't tell anything about shadowing
 729                   in this case so skip shadow assignment. */
 730                if (0 != (size & 0x1fffff)){
 731                        /* Align to 512KB to ensure correct handling
 732                           of both memfile and system specified
 733                           sizes. */
 734                        size = ((size+0x0007ffff) & 0xfff80000);
 735                        /* If memory is 1MB aligned, assume
 736                           shadowing. */
 737                        shadow = !(size & 0x80000);
 738                }
 739
 740                /* Add the chunk that ADOS does not see. by aligning
 741                   the size to the nearest 2MB limit upwards.  */
 742                memory[0].size = ((size+0x001fffff) & 0xffe00000);
 743        }
 744
 745        ppc_memstart = memory[0].addr;
 746        ppc_memoffset = PAGE_OFFSET - PPC_MEMSTART;
 747        total = memory[0].size;
 748
 749        /* Remove the memory chunks that are controlled by special
 750           Phase5 hardware. */
 751
 752        /* Remove the upper 512KB if it contains a shadow of
 753           the ADOS ROM. FIXME: It might be possible to
 754           disable this shadow HW. Check the booter
 755           (ppc_boot.c) */
 756        if (shadow)
 757                total -= HARDWARE_MAPPED_SIZE;
 758
 759        /* Remove the upper 512KB where the PPC exception
 760           vectors are mapped. */
 761        total -= HARDWARE_MAPPED_SIZE;
 762
 763        /* Linux/APUS only handles one block of memory -- the one on
 764           the PowerUP board. Other system memory is horrible slow in
 765           comparison. The user can use other memory for swapping
 766           using the z2ram device. */
 767        return total;
 768}
 769
 770static void __init
 771apus_map_io(void)
 772{
 773        /* Map PPC exception vectors. */
 774        io_block_mapping(0xfff00000, 0xfff00000, 0x00020000, _PAGE_KERNEL);
 775        /* Map chip and ZorroII memory */
 776        io_block_mapping(zTwoBase,   0x00000000, 0x01000000, _PAGE_IO);
 777}
 778
 779__init
 780void apus_init_IRQ(void)
 781{
 782        struct irqaction *action;
 783        int i;
 784
 785#ifdef CONFIG_PCI
 786        apus_setup_pci_ptrs();
 787#endif
 788
 789        for ( i = 0 ; i < AMI_IRQS; i++ ) {
 790                irq_desc[i].status = IRQ_LEVEL;
 791                if (i < IRQ_AMIGA_AUTO) {
 792                        irq_desc[i].handler = &amiga_irqctrl;
 793                } else {
 794                        irq_desc[i].handler = &amiga_sys_irqctrl;
 795                        action = &amiga_sys_irqaction[i-IRQ_AMIGA_AUTO];
 796                        if (action->name)
 797                                setup_irq(i, action);
 798                }
 799        }
 800
 801        amiga_init_IRQ();
 802
 803}
 804
 805__init
 806void platform_init(unsigned long r3, unsigned long r4, unsigned long r5,
 807                   unsigned long r6, unsigned long r7)
 808{
 809        extern int parse_bootinfo(const struct bi_record *);
 810        extern char _end[];
 811
 812        /* Parse bootinfo. The bootinfo is located right after
 813           the kernel bss */
 814        parse_bootinfo((const struct bi_record *)&_end);
 815#ifdef CONFIG_BLK_DEV_INITRD
 816        /* Take care of initrd if we have one. Use data from
 817           bootinfo to avoid the need to initialize PPC
 818           registers when kernel is booted via a PPC reset. */
 819        if ( ramdisk.addr ) {
 820                initrd_start = (unsigned long) __va(ramdisk.addr);
 821                initrd_end = (unsigned long)
 822                        __va(ramdisk.size + ramdisk.addr);
 823        }
 824#endif /* CONFIG_BLK_DEV_INITRD */
 825
 826        ISA_DMA_THRESHOLD = 0x00ffffff;
 827
 828        ppc_md.setup_arch     = apus_setup_arch;
 829        ppc_md.show_cpuinfo   = apus_show_cpuinfo;
 830        ppc_md.init_IRQ       = apus_init_IRQ;
 831        ppc_md.get_irq        = apus_get_irq;
 832
 833#ifdef CONFIG_HEARTBEAT
 834        ppc_md.heartbeat      = apus_heartbeat;
 835        ppc_md.heartbeat_count = 1;
 836#endif
 837#ifdef APUS_DEBUG
 838        __debug_serinit();
 839        ppc_md.progress       = apus_progress;
 840#endif
 841        ppc_md.init           = NULL;
 842
 843        ppc_md.restart        = apus_restart;
 844        ppc_md.power_off      = apus_power_off;
 845        ppc_md.halt           = apus_halt;
 846
 847        ppc_md.time_init      = NULL;
 848        ppc_md.set_rtc_time   = apus_set_rtc_time;
 849        ppc_md.get_rtc_time   = apus_get_rtc_time;
 850        ppc_md.calibrate_decr = apus_calibrate_decr;
 851
 852        ppc_md.find_end_of_memory = apus_find_end_of_memory;
 853        ppc_md.setup_io_mappings = apus_map_io;
 854
 855        /* These should not be used for the APUS yet, since it uses
 856           the M68K keyboard now. */
 857        ppc_md.kbd_translate     = amiga_kbd_translate;
 858        ppc_md.kbd_unexpected_up = apus_kbd_unexpected_up;
 859}
 860
lxr.linux.no kindly hosted by Redpill Linpro AS, provider of Linux consulting and operations services since 1995.