📄 tgt_machdep.c
字号:
/* $Id: tgt_machdep.c,v 1.15 2003/08/30 14:54:46 pefo Exp $ *//* * Copyright (c) 2002 Momentum Computer (www.momenco.com) * Copyright (c) 2001 Opsycon AB (www.opsycon.se) * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * 3. All advertising materials mentioning features or use of this software * must display the following acknowledgement: * This product includes software developed by Opsycon AB, Sweden. * 4. The name of the author may not be used to endorse or promote products * derived from this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS * OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. * */#include <sys/param.h>#include <sys/syslog.h>#include <machine/endian.h>#include <sys/device.h>#include <machine/cpu.h>#include <machine/pio.h>#include <machine/intr.h>#include <dev/pci/pcivar.h>#include <sys/types.h>#include <termio.h>#include <string.h>#include <time.h>#include <stdlib.h>#include <autoconf.h>#include <machine/cpu.h>#include <machine/pio.h>#include <machine/rm9k.h>#include "pflash.h"#include "dev/pflash_tgt.h"#include "include/jaguar_atx.h"#include "include/fpga.h"#include <pmon/dev/mv64340reg.h>#include <pmon/dev/ns16550.h>#include "include/m48t37.h"#include <pmon.h>#include "flash.h"#if (NMOD_FLASH_AMD + NMOD_FLASH_INTEL) == 0#ifdef HAVE_FLASH#undef HAVE_FLASH#endif#else#define HAVE_FLASH#endif#define TOD_REG(x) (clkbase + x)extern char _end[];extern int discouart(int, struct DevEntry *, unsigned long, int);extern void *memset(void *, int, size_t);extern int _pmon_snap(void);static int md_pipefreq = 0;static int md_cpufreq = 0;static int clk_invalid = 0;static int nvram_invalid = 0;static int cksum __P((void *p, size_t s, int set));static void _probe_frequencies __P((void));ConfigEntry ConfigTable[] ={#if !defined(GTCONSOLE) { (char *)COM1_BASE_ADDR, 0, ns16550, 256, CONS_BAUD, NS16550HZ },#if !defined(NOCOM2) { (char *)2, 0, discouart, 256, CONS_BAUD, GTSYSCLK },#endif#else { (char *)2, 0, discouart, 256, CONS_BAUD, GTSYSCLK },#if !defined(NOCOM2) { (char *)COM1_BASE_ADDR, 0, ns16550, 256, CONS_BAUD, NS16550HZ },#endif#endif#if 0 /* This port is not wired */ { (char *)COM2_BASE_ADDR, 0, ns16550, 256, CONS_BAUD, NS16550HZ },#endif { 0 }};/* Semaphores */int spinlock, usem0, usem1, usem2, usem3;unsigned long _filebase;extern char MipsException[], MipsExceptionEnd[];char unsigned hwethadr[6];void initmips(void *, void *);voidinitmips(void *rm9k_size, void *mv64340_size){ void *totalsize; /* * Set up initial memory arena. */ totalsize = rm9k_size + (long)mv64340_size; totalmemsize = (long)totalsize; if (in8(FPGAREG(BOARD_STAT)) & BOARD_USER) { kmemtop = mv64340_size; } else { kmemtop = totalsize; } SBD_DISPLAY ("MSIZ", CHKPNT_AUTO); /* Adjust PCI drive strength -- this should be automatic, but * for some reason the auto-cal doesn't work properly * We need to do this here to give the settings time to work. */ GT_WRITE(PCI0_PADS_CALIBRATION, 0x80000000); GT_WRITE(PCI0_PADS_CALIBRATION, 0x00004444); GT_WRITE(PCI1_PADS_CALIBRATION, 0x80000000); GT_WRITE(PCI1_PADS_CALIBRATION, 0x00004444); /* * Set up memory address decoders to map entire memory. * But first move away bootrom map to high memory. */ GT_WRITE(BOOTCS_BASE_ADDRESS, BOOT_BASE >> 16); GT_WRITE(BOOTCS_SIZE, (BOOT_SIZE - 1) >> 16); /* * Probe clock frequencys so delays will work properly. */ tgt_cpufreq(); /* * Set up exception vectors. */ bcopy(MipsException, (char *)TLB_MISS_EXC_VEC, MipsExceptionEnd - MipsException); bcopy(MipsException, (char *)GEN_EXC_VEC, MipsExceptionEnd - MipsException); CpuOnboardCacheOn = 1; CPU_ConfigCache(); CPU_FlushCache(); CPU_SetSR(0, SR_BOOT_EXC_VEC); /* * Init PMON and debug */ cpuinfotab[0] = md_getcpuinfoptr(); cpuinfotab[1] = md_getcpuinfoptr() - 16384; /* XXX Coherency BUG! */ dbginit(NULL); CPU_ConfigCache(); /* Allow env to affect cache settings! */ /* * Register initial memory map. */ register_mem((void *)0, (void *)totalmemsize-1, MEM_RAM, "SDRAM"); if (in8(FPGAREG(BOARD_STAT)) & BOARD_USER) { register_mem((void *)0, mv64340_size-1, MEM_RAM, "on MV64340"); register_mem(mv64340_size, totalsize-1, MEM_RAM, "on RM9000"); } else { register_mem((void *)0, rm9k_size-1, MEM_RAM, "on RM9000"); register_mem(rm9k_size, totalsize-1, MEM_RAM, "on MV64340"); } register_mem((void *)PKT_SRAM_BASE, (void *)PKT_SRAM_BASE+PKT_SRAM_SIZE-1, MEM_RAM, "Packet Ram"); register_mem((void *)UNCACHED_TO_PHYS(RM9K_BASE_ADDR), (void *)UNCACHED_TO_PHYS(RM9K_BASE_ADDR)+0x3fff, MEM_IO, "OCD registers"); register_mem((void *)CACHED_TO_PHYS(memtop), kmemtop-1, MEM_DATA, "Kernel data"); register_mem((void *)0, (void *)CACHED_TO_PHYS(_end)-1, MEM_CODE, "PMON2000"); register_mem((void *)CACHED_TO_PHYS(_end), (void *)CACHED_TO_PHYS(heaptop)-1, MEM_DATA, "PMON2000 heap"); register_mem((void *)FPGA_BASE, (void *)BOOT_BASE+BOOT_SIZE-1, MEM_IO, "decoded space"); register_mem((void *)FPGA_BASE, (void *)FPGA_BASE+FPGA_SIZE-1, MEM_IO, "fpga control"); register_mem((void *)RTC_BASE, (void *)RTC_BASE+RTC_SIZE-1, MEM_IO, "RTC and NVRAM"); register_mem((void *)UART_BASE, (void *)UART_BASE+UART_SIZE-1, MEM_IO, "NS16552"); register_mem((void *)FLASH_BASE, (void *)FLASH_BASE+FLASH_SIZE-1, MEM_FLASH, "DiskOnChip"); register_mem((void *)OC_SRAM_BASE, (void *)OC_SRAM_BASE+OC_SRAM_SIZE-1, MEM_RAM, "on chip SRAM"); register_mem((void *)GT_BASE_ADDR, (void *)GT_BASE_ADDR+65535, MEM_IO, "internal registers"); register_mem((void *)0xffc00000, (void *)0xffc7ffff, MEM_FLASH, "boot flash"); _pmon_snap(); /* Take a register snapshot */ /* * Launch! */ pmon_main();}/* * Put all machine dependent initialization here. This call * is done after console has been initialized so it's safe * to output configuration and debug information with printf. */voidtgt_devconfig(){ _pci_devinit(1); /* PCI device initialization */ /* configure internal arbiter for PCI0 */ GT_WRITE(MPP_CONTROL0, 0x00001111); GT_WRITE(PCI_0_ARBITER, 0x80000030); GT_WRITE(MPP_CONTROL2, 0x00001111); GT_WRITE(PCI_1_ARBITER, 0x80000030); config_init(); configure();}/* functions to get the MAC address from the EEPROM */void burn_clocks(void);int exchange_bit(int val, int cs);void get_mac(char dest[6]);/* this function needs to burn at least 1us -- should be more than plenty */void burn_clocks(void){ int i; for (i = 0; i < 0x10000; i++) ;}int exchange_bit(int val, int cs){ /* place the data */ out8(FPGAREG(EEPROM), (val << 2) | cs); burn_clocks(); /* turn the clock on */ out8(FPGAREG(EEPROM), (val << 2) | cs | 0x2); burn_clocks(); /* turn the clock off and read-strobe */ out8(FPGAREG(EEPROM), (val << 2) | cs | 0x10); /* return the data */ return ((in8(FPGAREG(EEPROM)) >> 3) & 0x1);}void get_mac(char dest[6]){ char read_opcode[12] = {1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}; int i,j; for (i = 0; i < 12; i++) exchange_bit(read_opcode[i], 1); for (j = 0; j < 6; j++) { dest[j] = 0; for (i = 0; i < 8; i++) { dest[j] <<= 1; dest[j] |= exchange_bit(0, 1); } } /* turn off CS */ exchange_bit(0,0);}voidtgt_devinit(){ u_int32_t regval; /* * Gather info about and configure caches. */ if(getenv("ocache_off")) { CpuOnboardCacheOn = 0; } else { CpuOnboardCacheOn = 1; } if(getenv("ecache_off")) { CpuExternalCacheOn = 0; } else { CpuExternalCacheOn = 1; } /* Register Discovery area where PCI lives */ register_mem((void *)0xc0000000, (void *)0xffffffff, MEM_IO, "MV64340 I/O"); _pci_businit(1); /* PCI bus initialization */ /* * Set up the Access control stuff for ethernet. */ /* Map SDRAM */ regval = 0x20; /* Disable BAR5 */ regval |= GT_READ(CPU_BASE_ADDRESS_ENABLE) & 0x0f; GT_WRITE(ETH_BASE_ADDR_ENABLE_REG, regval); regval = GT_READ(SCS_0_BASE_ADDRESS) << 16; GT_WRITE(ETH_BAR_0, (regval & 0xffff0000) | 0x0e00); regval = GT_READ(SCS_0_SIZE) << 16; GT_WRITE(ETH_SIZE_REG_0, regval & 0xffff0000); GT_WRITE(ETH_HIGH_ADDR_REMAP_REG_0, 0); regval = GT_READ(SCS_1_BASE_ADDRESS) << 16; GT_WRITE(ETH_BAR_1, (regval & 0xffff0000) | 0x0d00); regval = GT_READ(SCS_1_SIZE) << 16; GT_WRITE(ETH_SIZE_REG_1, regval & 0xffff0000); GT_WRITE(ETH_HIGH_ADDR_REMAP_REG_1, 0); regval = GT_READ(SCS_2_BASE_ADDRESS) << 16; GT_WRITE(ETH_BAR_2, (regval & 0xffff0000) | 0x0b00); regval = GT_READ(SCS_2_SIZE) << 16; GT_WRITE(ETH_SIZE_REG_2, regval & 0xffff0000); GT_WRITE(ETH_HIGH_ADDR_REMAP_REG_2, 0); regval = GT_READ(SCS_3_BASE_ADDRESS) << 16; GT_WRITE(ETH_BAR_3, (regval & 0xffff0000) | 0x0700); regval = GT_READ(SCS_3_SIZE) << 16; GT_WRITE(ETH_SIZE_REG_3, regval & 0xffff0000); GT_WRITE(ETH_HIGH_ADDR_REMAP_REG_3, 0); /* Map internal SRAM */ GT_WRITE(ETH_BAR_4, OC_SRAM_BASE | 0x02); GT_WRITE(ETH_SIZE_REG_4, (OC_SRAM_SIZE - 1) & 0xffff0000); /* R/W access for all ports */ GT_WRITE(ETH_ACCESS_PROTECTION_REG(0), 0x0fff); GT_WRITE(ETH_ACCESS_PROTECTION_REG(2), 0x0fff); GT_WRITE(ETH_ACCESS_PROTECTION_REG(1), 0x0fff); /* Load the MAC address from the EEPROM. * It is also in the NVRAM, and that copy can be gotten to with: * memcpy(hwethadr, (void *)NVRAM_ENETADDR, 6); */ get_mac(hwethadr);}voidtgt_reboot(){ int i; /* Reset reset cause */ out8(FPGAREG(RESET_STAT), in8(FPGAREG(RESET_STAT))); /* Enable watchdog one tick at 1/16th second */ out8(M48T37_BASE+7, 0x84); /* Then wait... */ for(i = 0; i < 200000000; i++) ; /* Unreliable but try this if watchdog fails... */ printf("Watchdog reboot failed!\n"); while(1);}/* * This function makes inital HW setup for debugger and * returns the apropriate setting for the status register. */register_ttgt_enable(int machtype){ /* XXX Do any HW specific setup */ return(SR_COP_1_BIT|SR_FR_32|SR_EXL);}/* * Target dependent version printout. * Printout available target version information. */voidtgt_cmd_vers(){ printf("Board revision level: %c.\n", in8(FPGAREG(REVISION)) + 'A'); printf("FPGA revision level: %d.%d.\n", in8(FPGAREG(FPGA_REV)) >> 4, in8(FPGAREG(FPGA_REV)) & 15);}/* * Display any target specific logo. */#if defined(HAVE_LOGO)voidtgt_logo(){}#endifstatic void_probe_frequencies(){#ifdef HAVE_TOD int i, timeout, cur, sec, cnt; int clkbase = M48T37_BASE;#endif SBD_DISPLAY ("FREQ", CHKPNT_FREQ); md_pipefreq = 300000000; /* Defaults */ md_cpufreq = 100000000; clk_invalid = 1;#ifdef HAVE_TOD /* * Check if clock is stopped and start it if it is. */ if(inb(TOD_REG(TOD_SECOND)) & TOD_SECOND_ST) { outb(TOD_REG(TOD_SECOND), inb(TOD_REG(TOD_SECOND)) & ~TOD_SECOND_ST); } else { clk_invalid = 0; } /* * Do the next twice for two reasons. First make sure we run from * cache. Second make sure synched on second update. (Pun intended!) */ for(i = 2; i != 0; i--) { cnt = CPU_GetCOUNT(); timeout = 100000000; /* stop update */ outb(TOD_REG(TOD_CTRL), inb(TOD_REG(TOD_CTRL)) | TOD_CTRL_R); sec = inb(TOD_REG(TOD_SECOND)) & 0x0f; /* start update */ outb(TOD_REG(TOD_CTRL), inb(TOD_REG(TOD_CTRL)) & ~TOD_CTRL_R); /* Loop for one sec, and see how many ticks we get. * Time out after (timeout) times through the loop. */ do { timeout--; /* stop update */ outb(TOD_REG(TOD_CTRL), inb(TOD_REG(TOD_CTRL)) | TOD_CTRL_R); cur = inb(TOD_REG(TOD_SECOND)) & 0x0f; /* start update */ outb(TOD_REG(TOD_CTRL), inb(TOD_REG(TOD_CTRL)) & ~TOD_CTRL_R); } while(timeout != 0 && cur == sec); cnt = CPU_GetCOUNT() - cnt; if(timeout == 0) { clk_invalid = 1; return; /* Get out if clock is not running */ } } /* * Calculate the external bus clock frequency. * Here we calculate the CPU frequency based on the pipeline time. * Yes, md_pipefreq is really the CPU speed. */ md_pipefreq = (cnt + 5999)/ 10000; md_pipefreq *= 20000; /* Check TimerX1 bit */ if(RM9K_READ(RM9K_CONF064) & (1 << (79-64))) md_pipefreq /= 2; /* * Calculate the external frequency. */ clkbase = (RM9K_READ(RM9K_CONF128) >> (141-128)) & 0x1f; if (clkbase == 0x1f) { md_cpufreq = md_pipefreq; } else { md_cpufreq = md_pipefreq / (clkbase + 2); } clkbase = (RM9K_READ(RM9K_CONF128) >> (136-128)) & 0x1f; if (clkbase != 0x1f) { md_cpufreq = md_cpufreq / (clkbase + 2); } if(RM9K_READ(RM9K_CONF128) & (1 << (135-128))) md_cpufreq *= 2;#endif /* HAVE_TOD */}/* * Returns the CPU pipelie clock frequency */inttgt_pipefreq(){ if(md_pipefreq == 0) { _probe_frequencies(); } return(md_pipefreq);}/* * Returns the external clock frequency, usually the bus clock */inttgt_cpufreq(){ if(md_cpufreq == 0) { _probe_frequencies(); } return(md_cpufreq);}#ifdef HAVE_TOD/* * Returns the current time if a TOD clock is present or 0 * This code is defunct after 2088... (out of bits) */#define FROMBCD(x) (((x) >> 4) * 10 + ((x) & 0xf))#define TOBCD(x) (((x) / 10 * 16) + ((x) % 10)) #define YEARDAYS(year) ((((year) % 4) == 0 && \ ((year % 100) != 0 || (year % 400) == 0)) ? 366 : 365)#define SECMIN (60) /* seconds per minute */#define SECHOUR (60*SECMIN) /* seconds per hour */#define SECDAY (24*SECHOUR) /* seconds per day */#define SECYR (365*SECDAY) /* seconds per common year */static const short dayyr[12] = { 0, 31, 59, 90, 120, 151, 181, 212, 243, 273, 304, 334 };time_ttgt_gettime(){ struct tm tm; int clkbase = M48T37_BASE; int century; time_t t; if(clk_invalid) { tm.tm_sec = 0; tm.tm_min = 0; tm.tm_hour = 0; tm.tm_wday = 0; tm.tm_mday = 1; tm.tm_mon = 1; tm.tm_year = 0; } else { outb(TOD_REG(TOD_CTRL), inb(TOD_REG(TOD_CTRL)) | TOD_CTRL_R); tm.tm_sec = FROMBCD(inb(TOD_REG(TOD_SECOND))); tm.tm_min = FROMBCD(inb(TOD_REG(TOD_MINUTE))); tm.tm_hour = FROMBCD(inb(TOD_REG(TOD_HOUR))); tm.tm_wday = FROMBCD(inb(TOD_REG(TOD_DAY))); tm.tm_mday = FROMBCD(inb(TOD_REG(TOD_DATE))); tm.tm_mon = FROMBCD(inb(TOD_REG(TOD_MONTH))) - 1; tm.tm_year = FROMBCD(inb(TOD_REG(TOD_YEAR))); century = FROMBCD(inb(TOD_REG(TOD_CENTURY))); outb(TOD_REG(TOD_CTRL), inb(TOD_REG(TOD_CTRL)) & ~TOD_CTRL_R); } /* Since tm_year is defined to be years since 1900 we compute */ /* the correct value here */ tm.tm_year = century*100 + tm.tm_year - 1900; tm.tm_isdst = tm.tm_gmtoff = 0; t = gmmktime(&tm); if(clk_invalid) { tgt_settime(t); } return(t);}/* * Set the current time if a TOD clock is present */voidtgt_settime(time_t t){ struct tm *tm; int clkbase = M48T37_BASE; int century; tm = gmtime(&t); /* Enable register writing */ outb(TOD_REG(TOD_CTRL), inb(TOD_REG(TOD_CTRL)) | TOD_CTRL_W); century = (tm->tm_year + 1900)/100; outb(TOD_REG(TOD_CENTURY), TOBCD(century)); outb(TOD_REG(TOD_YEAR), TOBCD((tm->tm_year + 1900) % 100));
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -