📄 apus_setup.c
字号:
/* * linux/arch/ppc/kernel/apus_setup.c * * Copyright (C) 1998, 1999 Jesper Skov * * Basically what is needed to replace functionality found in * arch/m68k allowing Amiga drivers to work under APUS. * Bits of code and/or ideas from arch/m68k and arch/ppc files. * * TODO: * This file needs a *really* good cleanup. Restructure and optimize. * Make sure it can be compiled for non-APUS configs. Begin to move * Amiga specific stuff into mach/amiga. */#include <linux/config.h>#include <linux/types.h>#include <linux/kernel.h>#include <linux/sched.h>#include <linux/kd.h>#include <linux/init.h>#include <linux/hdreg.h>#include <linux/blk.h>#include <linux/pci.h>#ifdef CONFIG_APUS#include <asm/logging.h>#endif/* Needs INITSERIAL call in head.S! */#undef APUS_DEBUG#include <linux/ide.h>#define T_CHAR (0x0000) /* char: don't touch */#define T_SHORT (0x4000) /* short: 12 -> 21 */#define T_INT (0x8000) /* int: 1234 -> 4321 */#define T_TEXT (0xc000) /* text: 12 -> 21 */#define T_MASK_TYPE (0xc000)#define T_MASK_COUNT (0x3fff)#define D_CHAR(cnt) (T_CHAR | (cnt))#define D_SHORT(cnt) (T_SHORT | (cnt))#define D_INT(cnt) (T_INT | (cnt))#define D_TEXT(cnt) (T_TEXT | (cnt))static u_short driveid_types[] = { D_SHORT(10), /* config - vendor2 */ D_TEXT(20), /* serial_no */ D_SHORT(3), /* buf_type, buf_size - ecc_bytes */ D_TEXT(48), /* fw_rev - model */ D_CHAR(2), /* max_multsect - vendor3 */ D_SHORT(1), /* dword_io */ D_CHAR(2), /* vendor4 - capability */ D_SHORT(1), /* reserved50 */ D_CHAR(4), /* vendor5 - tDMA */ D_SHORT(4), /* field_valid - cur_sectors */ D_INT(1), /* cur_capacity */ D_CHAR(2), /* multsect - multsect_valid */ D_INT(1), /* lba_capacity */ D_SHORT(194) /* dma_1word - reservedyy */};#define num_driveid_types (sizeof(driveid_types)/sizeof(*driveid_types))#include <asm/bootinfo.h>#include <asm/setup.h>#include <asm/amigahw.h>#include <asm/amigaints.h>#include <asm/amigappc.h>#include <asm/pgtable.h>#include <asm/io.h>#include <asm/dma.h>#include <asm/machdep.h>#include <asm/init.h>#include "local_irq.h"unsigned long m68k_machtype __apusdata;char debug_device[6] __apusdata = "";extern void amiga_init_IRQ(void);void (*mach_sched_init) (void (*handler)(int, void *, struct pt_regs *)) __initdata = NULL;/* machine dependent keyboard functions */int (*mach_keyb_init) (void) __initdata = NULL;int (*mach_kbdrate) (struct kbd_repeat *) __apusdata = NULL;void (*mach_kbd_leds) (unsigned int) __apusdata = NULL;/* machine dependent irq functions */void (*mach_init_IRQ) (void) __initdata = NULL;void (*(*mach_default_handler)[]) (int, void *, struct pt_regs *) __apusdata = NULL;void (*mach_get_model) (char *model) __apusdata = NULL;int (*mach_get_hardware_list) (char *buffer) __apusdata = NULL;int (*mach_get_irq_list) (char *) __apusdata = NULL;void (*mach_process_int) (int, struct pt_regs *) __apusdata = NULL;/* machine dependent timer functions */unsigned long (*mach_gettimeoffset) (void) __apusdata;void (*mach_gettod) (int*, int*, int*, int*, int*, int*) __apusdata;int (*mach_hwclk) (int, struct hwclk_time*) __apusdata = NULL;int (*mach_set_clock_mmss) (unsigned long) __apusdata = NULL;void (*mach_reset)( void ) __apusdata;long mach_max_dma_address __apusdata = 0x00ffffff; /* default set to the lower 16MB */#if defined(CONFIG_AMIGA_FLOPPY)void (*mach_floppy_setup) (char *, int *) __initdata = NULL;void (*mach_floppy_eject) (void) __apusdata = NULL;#endif#ifdef CONFIG_HEARTBEATvoid (*mach_heartbeat) (int) __apusdata = NULL;extern void apus_heartbeat (void);#endifextern unsigned long amiga_model;extern unsigned decrementer_count;/* count value for 1e6/HZ microseconds */extern unsigned count_period_num; /* 1 decrementer count equals */extern unsigned count_period_den; /* count_period_num / count_period_den us */int num_memory __apusdata = 0;struct mem_info memory[NUM_MEMINFO] __apusdata;/* memory description *//* FIXME: Duplicate memory data to avoid conflicts with m68k shared code. */int m68k_realnum_memory __apusdata = 0;struct mem_info m68k_memory[NUM_MEMINFO] __apusdata;/* memory description */struct mem_info ramdisk __apusdata;extern void amiga_floppy_setup(char *, int *);extern void config_amiga(void);static int __60nsram __apusdata = 0;/* for cpuinfo */static int __bus_speed __apusdata = 0;static int __speed_test_failed __apusdata = 0;/********************************************** COMPILE PROTECTION *//* Provide some stubs that links to Amiga specific functions. * This allows CONFIG_APUS to be removed from generic PPC files while * preventing link errors for other PPC targets. */__apusunsigned long apus_get_rtc_time(void){#ifdef CONFIG_APUS extern unsigned long m68k_get_rtc_time(void); return m68k_get_rtc_time ();#else return 0;#endif}__apusint apus_set_rtc_time(unsigned long nowtime){#ifdef CONFIG_APUS extern int m68k_set_rtc_time(unsigned long nowtime); return m68k_set_rtc_time (nowtime);#else return 0;#endif}/* Here some functions we don't support, but which the other ports reference */int pckbd_setkeycode(unsigned int scancode, unsigned int keycode){ printk("Bogus call to " __FILE__ ":" __FUNCTION__ "\n"); return 0; }int pckbd_getkeycode(unsigned int scancode) { printk("Bogus call to " __FILE__ ":" __FUNCTION__ "\n"); return 0; }int pckbd_translate(unsigned char scancode, unsigned char *keycode, char raw_mode) { printk("Bogus call to " __FILE__ ":" __FUNCTION__ "\n"); return 0; }char pckbd_unexpected_up(unsigned char keycode){ printk("Bogus call to " __FILE__ ":" __FUNCTION__ "\n"); return 0;}void pckbd_leds(unsigned char leds){ printk("Bogus call to " __FILE__ ":" __FUNCTION__ "\n");}void pckbd_init_hw(void){ printk("Bogus call to " __FILE__ ":" __FUNCTION__ "\n");}unsigned char pckbd_sysrq_xlate[128];struct pci_bus * __init pci_scan_peer_bridge(int bus){ printk("Bogus call to " __FILE__ ":" __FUNCTION__ "\n"); return NULL;}/*********************************************************** SETUP *//* From arch/m68k/kernel/setup.c. */void __init apus_setup_arch(void){#ifdef CONFIG_APUS extern char cmd_line[]; int i; char *p, *q; /* Let m68k-shared code know it should do the Amiga thing. */ m68k_machtype = MACH_AMIGA; /* Parse the command line for arch-specific options. * For the m68k, this is currently only "debug=xxx" to enable printing * certain kernel messages to some machine-specific device. */ for( p = cmd_line; p && *p; ) { i = 0; if (!strncmp( p, "debug=", 6 )) { strncpy( debug_device, p+6, sizeof(debug_device)-1 ); debug_device[sizeof(debug_device)-1] = 0; if ((q = strchr( debug_device, ' ' ))) *q = 0; i = 1; } else if (!strncmp( p, "60nsram", 7 )) { APUS_WRITE (APUS_REG_WAITSTATE, REGWAITSTATE_SETRESET |REGWAITSTATE_PPCR |REGWAITSTATE_PPCW); __60nsram = 1; i = 1; } if (i) { /* option processed, delete it */ if ((q = strchr( p, ' ' ))) strcpy( p, q+1 ); else *p = 0; } else { if ((p = strchr( p, ' ' ))) ++p; } } config_amiga();#if 0 /* Enable for logging - also include logging.o in Makefile rule */ {#define LOG_SIZE 4096 void* base; /* Throw away some memory - the P5 firmare stomps on top * of CHIP memory during bootup. */ amiga_chip_alloc(0x1000); base = amiga_chip_alloc(LOG_SIZE+sizeof(klog_data_t)); LOG_INIT(base, base+sizeof(klog_data_t), LOG_SIZE); }#endif#endif}__apusintapus_get_cpuinfo(char *buffer){#ifdef CONFIG_APUS extern int __map_without_bats; extern unsigned long powerup_PCI_present; int len; len = sprintf(buffer, "machine\t\t: Amiga\n"); len += sprintf(buffer+len, "bus speed\t: %d%s", __bus_speed, (__speed_test_failed) ? " [failed]\n" : "\n"); len += sprintf(buffer+len, "using BATs\t: %s\n", (__map_without_bats) ? "No" : "Yes"); len += sprintf(buffer+len, "ram speed\t: %dns\n", (__60nsram) ? 60 : 70); len += sprintf(buffer+len, "PCI bridge\t: %s\n", (powerup_PCI_present) ? "Yes" : "No"); return len;#endif}__apusstatic void get_current_tb(unsigned long long *time){ __asm __volatile ("1:mftbu 4 \n\t" " mftb 5 \n\t" " mftbu 6 \n\t" " cmpw 4,6 \n\t" " bne 1b \n\t" " stw 4,0(%0)\n\t" " stw 5,4(%0)\n\t" : : "r" (time) : "r4", "r5", "r6");}__apusvoid apus_calibrate_decr(void){#ifdef CONFIG_APUS unsigned long freq; /* This algorithm for determining the bus speed was contributed by Ralph Schmidt. */ unsigned long long start, stop; int bus_speed; int speed_test_failed = 0; { unsigned long loop = amiga_eclock / 10; get_current_tb (&start); while (loop--) { unsigned char tmp; tmp = ciaa.pra; } get_current_tb (&stop); } bus_speed = (((unsigned long)(stop-start))*10*4) / 1000000; if (AMI_1200 == amiga_model) bus_speed /= 2; if ((bus_speed >= 47) && (bus_speed < 53)) { bus_speed = 50; freq = 12500000; } else if ((bus_speed >= 57) && (bus_speed < 63)) { bus_speed = 60; freq = 15000000; } else if ((bus_speed >= 63) && (bus_speed < 69)) { bus_speed = 67; freq = 16666667; } else { printk ("APUS: Unable to determine bus speed (%d). " "Defaulting to 50MHz", bus_speed); bus_speed = 50; freq = 12500000; speed_test_failed = 1; } /* Ease diagnostics... */ { extern int __map_without_bats; extern unsigned long powerup_PCI_present; printk ("APUS: BATs=%d, BUS=%dMHz", (__map_without_bats) ? 0 : 1, bus_speed); if (speed_test_failed) printk ("[FAILED - please report]"); printk (", RAM=%dns, PCI bridge=%d\n", (__60nsram) ? 60 : 70, (powerup_PCI_present) ? 1 : 0); /* print a bit more if asked politely... */ if (!(ciaa.pra & 0x40)){ extern unsigned int bat_addrs[4][3]; int b; for (b = 0; b < 4; ++b) { printk ("APUS: BAT%d ", b); printk ("%08x-%08x -> %08x\n", bat_addrs[b][0], bat_addrs[b][1], bat_addrs[b][2]); } } } printk("time_init: decrementer frequency = %lu.%.6lu MHz\n", freq/1000000, freq%1000000); tb_ticks_per_jiffy = freq / HZ; tb_to_us = mulhwu_scale_factor(freq, 1000000); __bus_speed = bus_speed; __speed_test_failed = speed_test_failed;#endif}__apusvoid arch_gettod(int *year, int *mon, int *day, int *hour, int *min, int *sec){#ifdef CONFIG_APUS if (mach_gettod) mach_gettod(year, mon, day, hour, min, sec); else *year = *mon = *day = *hour = *min = *sec = 0;#endif}/* for "kbd-reset" cmdline param */__initvoid kbd_reset_setup(char *str, int *ints){}/*********************************************************** FLOPPY */#if defined(CONFIG_AMIGA_FLOPPY)__init void floppy_setup(char *str, int *ints){ if (mach_floppy_setup) mach_floppy_setup (str, ints);}__apusvoid floppy_eject(void){ if (mach_floppy_eject) mach_floppy_eject();}#endif/*********************************************************** MEMORY */#define KMAP_MAX 32unsigned long kmap_chunks[KMAP_MAX*3] __apusdata;int kmap_chunk_count __apusdata = 0;/* From pgtable.h */__apusstatic __inline__ pte_t *my_find_pte(struct mm_struct *mm,unsigned long va){ pgd_t *dir = 0; pmd_t *pmd = 0; pte_t *pte = 0; va &= PAGE_MASK; dir = pgd_offset( mm, va ); if (dir) { pmd = pmd_offset(dir, va & PAGE_MASK); if (pmd && pmd_present(*pmd)) { pte = pte_offset(pmd, va); } } return pte;}/* Again simulating an m68k/mm/kmap.c function. */__apusvoid kernel_set_cachemode( unsigned long address, unsigned long size, unsigned int cmode ){ unsigned long mask, flags; switch (cmode) { case IOMAP_FULL_CACHING: mask = ~(_PAGE_NO_CACHE | _PAGE_GUARDED); flags = 0; break; case IOMAP_NOCACHE_SER: mask = ~0; flags = (_PAGE_NO_CACHE | _PAGE_GUARDED); break; default: panic ("kernel_set_cachemode() doesn't support mode %d\n", cmode); break; } size /= PAGE_SIZE; address &= PAGE_MASK; while (size--) { pte_t *pte; pte = my_find_pte(&init_mm, address); if ( !pte ) { printk("pte NULL in kernel_set_cachemode()\n"); return; } pte_val (*pte) &= mask; pte_val (*pte) |= flags; flush_tlb_page(find_vma(&init_mm,address),address); address += PAGE_SIZE; }}__apusunsigned long mm_ptov (unsigned long paddr){ unsigned long ret; if (paddr < 16*1024*1024) ret = ZTWO_VADDR(paddr); else { int i; for (i = 0; i < kmap_chunk_count;){ unsigned long phys = kmap_chunks[i++]; unsigned long size = kmap_chunks[i++]; unsigned long virt = kmap_chunks[i++]; if (paddr >= phys && paddr < (phys + size)){ ret = virt + paddr - phys; goto exit; } } ret = (unsigned long) __va(paddr); }exit:#ifdef DEBUGPV printk ("PTOV(%lx)=%lx\n", paddr, ret);#endif return ret;}__apusint mm_end_of_chunk (unsigned long addr, int len){ if (memory[0].addr + memory[0].size == addr + len) return 1; return 0;}/*********************************************************** CACHE */#define L1_CACHE_BYTES 32#define MAX_CACHE_SIZE 8192__apusvoid cache_push(__u32 addr, int length){ addr = mm_ptov(addr); if (MAX_CACHE_SIZE < length) length = MAX_CACHE_SIZE; while(length > 0){ __asm ("dcbf 0,%0\n\t" : : "r" (addr)); addr += L1_CACHE_BYTES; length -= L1_CACHE_BYTES; } /* Also flush trailing block */ __asm ("dcbf 0,%0\n\t" "sync \n\t" : : "r" (addr));}__apusvoid cache_clear(__u32 addr, int length){ if (MAX_CACHE_SIZE < length) length = MAX_CACHE_SIZE; addr = mm_ptov(addr); __asm ("dcbf 0,%0\n\t" "sync \n\t" "icbi 0,%0 \n\t" "isync \n\t" : : "r" (addr)); addr += L1_CACHE_BYTES; length -= L1_CACHE_BYTES; while(length > 0){ __asm ("dcbf 0,%0\n\t" "sync \n\t"
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -