From: James S. <jsi...@us...> - 2001-11-08 17:42:11
|
Update of /cvsroot/linux-mips/linux/arch/mips/sibyte/swarm In directory usw-pr-cvs1:/tmp/cvs-serv7520/sibyte/swarm Added Files: Makefile cfe_api.c cfe_api.h cfe_error.h cfe_xiocb.h cmdline.c memory.c rtc.c setup.c smp.c time.c Log Message: Cleanup Makefile crap and add support for Sibyte SB1250 / SWARM. --- NEW FILE: Makefile --- .S.s: $(CPP) $(AFLAGS) $< -o $@ .S.o: $(CC) $(AFLAGS) -c $< -o $@ EXTRA_AFLAGS = -mips3 -mcpu=r4000 all: sbswarm.a OBJS-y = setup.o cmdline.o rtc.o time.o memory.o cfe_api.o OBJS-$(CONFIG_SMP) += smp.o OBJS-$(CONFIG_L3DEMO) += procl3switch.o l3procbootstrap.o l3proc.o OBJS-$(CONFIG_REMOTE_DEBUG) += dbg_io.o #XMITTER=1 ifdef XMITTER l3proc.bin: xmitter ln xmitter l3proc.bin else l3proc.bin: l3proc ln l3proc l3proc.bin endif l3proc.o: l3proc.bin mips-linux-ld -Tl3proc.lds -bbinary -o l3proc.o l3proc.bin sbswarm.a: $(OBJS-y) $(AR) rcs sbswarm.a $^ rm -f l3proc.o l3proc.bin include $(TOPDIR)/Rules.make --- NEW FILE: cfe_api.c --- /* * Copyright (C) 2000, 2001 Broadcom Corporation * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License * as published by the Free Software Foundation; either version 2 * of the License, or (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ /* ********************************************************************* * Broadcom Common Firmware Environment (CFE) * * Device Function stubs File: cfe_api.c * * This module contains device function stubs (small routines to * call the standard "iocb" interface entry point to CFE). * There should be one routine here per iocb function call. * * Author: Mitch Lichtenberg (mp...@br...) * ********************************************************************* */ #include "cfe_xiocb.h" #include "cfe_api.h" #include <linux/string.h> static long cfe_console_handle = -1; static int (*cfe_dispfunc)(long handle,cfe_xiocb_t *xiocb) = 0; static cfe_xuint_t cfe_handle = 0; /* * This macro makes a "signed 64-bit pointer" - basically extending a regular * pointer to its 64-bit compatibility space equivalent. */ #define BIGPTR(x) (long long) (long) (x) typedef unsigned long intptr_t; int cfe_init(cfe_xuint_t handle) { unsigned int *sealloc = (unsigned int *) (intptr_t) (int) CFE_APISEAL; if (*sealloc != CFE_EPTSEAL) return -1; cfe_dispfunc = (void *) (cfe_xptr_t) (int) CFE_APIENTRY; if (handle) cfe_handle = handle; return 0; } int cfe_iocb_dispatch(cfe_xiocb_t *xiocb); int cfe_iocb_dispatch(cfe_xiocb_t *xiocb) { if (!cfe_dispfunc) return -1; return (*cfe_dispfunc)(cfe_handle,xiocb); } static int cfe_strlen(char *name) { int count = 0; while (*name) { count++; name++; } return count; } int cfe_open(char *name) { cfe_xiocb_t xiocb; xiocb.xiocb_fcode = CFE_CMD_DEV_OPEN; xiocb.xiocb_status = 0; xiocb.xiocb_handle = 0; xiocb.xiocb_flags = 0; xiocb.xiocb_psize = sizeof(xiocb_buffer_t); xiocb.plist.xiocb_buffer.buf_offset = 0; xiocb.plist.xiocb_buffer.buf_ptr = BIGPTR(name); xiocb.plist.xiocb_buffer.buf_length = cfe_strlen(name); cfe_iocb_dispatch(&xiocb); return (xiocb.xiocb_status < 0) ? xiocb.xiocb_status : xiocb.xiocb_handle; } int cfe_close(int handle) { cfe_xiocb_t xiocb; xiocb.xiocb_fcode = CFE_CMD_DEV_CLOSE; xiocb.xiocb_status = 0; xiocb.xiocb_handle = handle; xiocb.xiocb_flags = 0; xiocb.xiocb_psize = 0; cfe_iocb_dispatch(&xiocb); return (xiocb.xiocb_status); } int cfe_readblk(int handle,cfe_xint_t offset,unsigned char *buffer,int length) { cfe_xiocb_t xiocb; xiocb.xiocb_fcode = CFE_CMD_DEV_READ; xiocb.xiocb_status = 0; xiocb.xiocb_handle = handle; xiocb.xiocb_flags = 0; xiocb.xiocb_psize = sizeof(xiocb_buffer_t); xiocb.plist.xiocb_buffer.buf_offset = offset; xiocb.plist.xiocb_buffer.buf_ptr = BIGPTR(buffer); xiocb.plist.xiocb_buffer.buf_length = length; cfe_iocb_dispatch(&xiocb); return (xiocb.xiocb_status < 0) ? xiocb.xiocb_status : xiocb.plist.xiocb_buffer.buf_retlen; } int cfe_read(int handle,unsigned char *buffer,int length) { return cfe_readblk(handle,0,buffer,length); } int cfe_writeblk(int handle,cfe_xint_t offset,unsigned char *buffer,int length) { cfe_xiocb_t xiocb; xiocb.xiocb_fcode = CFE_CMD_DEV_WRITE; xiocb.xiocb_status = 0; xiocb.xiocb_handle = handle; xiocb.xiocb_flags = 0; xiocb.xiocb_psize = sizeof(xiocb_buffer_t); xiocb.plist.xiocb_buffer.buf_offset = offset; xiocb.plist.xiocb_buffer.buf_ptr = BIGPTR(buffer); xiocb.plist.xiocb_buffer.buf_length = length; cfe_iocb_dispatch(&xiocb); return (xiocb.xiocb_status < 0) ? xiocb.xiocb_status : xiocb.plist.xiocb_buffer.buf_retlen; } int cfe_write(int handle,unsigned char *buffer,int length) { return cfe_writeblk(handle,0,buffer,length); } int cfe_ioctl(int handle,unsigned int ioctlnum,unsigned char *buffer,int length,int *retlen) { cfe_xiocb_t xiocb; xiocb.xiocb_fcode = CFE_CMD_DEV_IOCTL; xiocb.xiocb_status = 0; xiocb.xiocb_handle = handle; xiocb.xiocb_flags = 0; xiocb.xiocb_psize = sizeof(xiocb_buffer_t); xiocb.plist.xiocb_buffer.buf_ioctlcmd = (cfe_xint_t) ioctlnum; xiocb.plist.xiocb_buffer.buf_ptr = BIGPTR(buffer); xiocb.plist.xiocb_buffer.buf_length = length; cfe_iocb_dispatch(&xiocb); if (retlen) *retlen = xiocb.plist.xiocb_buffer.buf_retlen; return xiocb.xiocb_status; } int cfe_inpstat(int handle) { cfe_xiocb_t xiocb; xiocb.xiocb_fcode = CFE_CMD_DEV_INPSTAT; xiocb.xiocb_status = 0; xiocb.xiocb_handle = handle; xiocb.xiocb_flags = 0; xiocb.xiocb_psize = sizeof(xiocb_inpstat_t); xiocb.plist.xiocb_inpstat.inp_status = 0; cfe_iocb_dispatch(&xiocb); if (xiocb.xiocb_status < 0) return xiocb.xiocb_status; return xiocb.plist.xiocb_inpstat.inp_status; } long long cfe_getticks(void) { cfe_xiocb_t xiocb; xiocb.xiocb_fcode = CFE_CMD_FW_GETTIME; xiocb.xiocb_status = 0; xiocb.xiocb_handle = 0; xiocb.xiocb_flags = 0; xiocb.xiocb_psize = sizeof(xiocb_time_t); xiocb.plist.xiocb_time.ticks = 0; cfe_iocb_dispatch(&xiocb); return xiocb.plist.xiocb_time.ticks; } int cfe_getenv(char *name,char *dest,int destlen) { cfe_xiocb_t xiocb; *dest = 0; xiocb.xiocb_fcode = CFE_CMD_ENV_GET; xiocb.xiocb_status = 0; xiocb.xiocb_handle = 0; xiocb.xiocb_flags = 0; xiocb.xiocb_psize = sizeof(xiocb_envbuf_t); xiocb.plist.xiocb_envbuf.enum_idx = 0; xiocb.plist.xiocb_envbuf.name_ptr = BIGPTR(name); xiocb.plist.xiocb_envbuf.name_length = cfe_strlen(name); xiocb.plist.xiocb_envbuf.val_ptr = BIGPTR(dest); xiocb.plist.xiocb_envbuf.val_length = destlen; cfe_iocb_dispatch(&xiocb); return xiocb.xiocb_status; } int cfe_setenv(char *name,char *val) { cfe_xiocb_t xiocb; xiocb.xiocb_fcode = CFE_CMD_ENV_SET; xiocb.xiocb_status = 0; xiocb.xiocb_handle = 0; xiocb.xiocb_flags = 0; xiocb.xiocb_psize = sizeof(xiocb_envbuf_t); xiocb.plist.xiocb_envbuf.enum_idx = 0; xiocb.plist.xiocb_envbuf.name_ptr = BIGPTR(name); xiocb.plist.xiocb_envbuf.name_length = cfe_strlen(name); xiocb.plist.xiocb_envbuf.val_ptr = BIGPTR(val); xiocb.plist.xiocb_envbuf.val_length = cfe_strlen(val); cfe_iocb_dispatch(&xiocb); return xiocb.xiocb_status; } int cfe_enummem(long idx, unsigned long *addr, unsigned long *size, long *type) { cfe_xiocb_t xiocb; xiocb.xiocb_fcode = CFE_CMD_FW_MEMENUM; xiocb.xiocb_status = 0; xiocb.xiocb_handle = 0; xiocb.xiocb_flags = 0; xiocb.xiocb_psize = sizeof(xiocb_meminfo_t); xiocb.plist.xiocb_meminfo.mi_idx = idx; cfe_iocb_dispatch(&xiocb); (*addr) = xiocb.plist.xiocb_meminfo.mi_addr; (*size) = xiocb.plist.xiocb_meminfo.mi_size; (*type) = xiocb.plist.xiocb_meminfo.mi_type; return xiocb.xiocb_status; } int cfe_enumenv(int idx,char *name,int namelen,char *val,int vallen) { cfe_xiocb_t xiocb; xiocb.xiocb_fcode = CFE_CMD_ENV_SET; xiocb.xiocb_status = 0; xiocb.xiocb_handle = 0; xiocb.xiocb_flags = 0; xiocb.xiocb_psize = sizeof(xiocb_envbuf_t); xiocb.plist.xiocb_envbuf.enum_idx = idx; xiocb.plist.xiocb_envbuf.name_ptr = BIGPTR(name); xiocb.plist.xiocb_envbuf.name_length = namelen; xiocb.plist.xiocb_envbuf.val_ptr = BIGPTR(val); xiocb.plist.xiocb_envbuf.val_length = vallen; cfe_iocb_dispatch(&xiocb); return xiocb.xiocb_status; } int cfe_exit(int warm, int status) { cfe_xiocb_t xiocb; xiocb.xiocb_fcode = CFE_CMD_FW_RESTART; xiocb.xiocb_status = 0; xiocb.xiocb_handle = 0; xiocb.xiocb_flags = warm ? CFE_FLG_WARMSTART : 0; xiocb.xiocb_psize = sizeof(xiocb_exitstat_t); xiocb.plist.xiocb_exitstat.status = (cfe_xint_t) status; cfe_iocb_dispatch(&xiocb); return (xiocb.xiocb_status); } int cfe_flushcache(int flg) { cfe_xiocb_t xiocb; xiocb.xiocb_fcode = CFE_CMD_FW_FLUSHCACHE; xiocb.xiocb_status = 0; xiocb.xiocb_handle = 0; xiocb.xiocb_flags = flg; xiocb.xiocb_psize = 0; cfe_iocb_dispatch(&xiocb); return xiocb.xiocb_status; } int cfe_getstdhandle(int flg) { cfe_xiocb_t xiocb; xiocb.xiocb_fcode = CFE_CMD_DEV_GETHANDLE; xiocb.xiocb_status = 0; xiocb.xiocb_handle = 0; xiocb.xiocb_flags = flg; xiocb.xiocb_psize = 0; cfe_iocb_dispatch(&xiocb); return (xiocb.xiocb_status < 0) ? xiocb.xiocb_status : xiocb.xiocb_handle; } int cfe_start_cpu(int cpu, void (*fn)(void), long sp, long gp, long a1) { cfe_xiocb_t xiocb; xiocb.xiocb_fcode = CFE_CMD_FW_CPUCTL; xiocb.xiocb_status = 0; xiocb.xiocb_handle = 0; xiocb.xiocb_flags = 0; xiocb.xiocb_psize = sizeof(xiocb_cpuctl_t); xiocb.plist.xiocb_cpuctl.cpu_number = cpu; xiocb.plist.xiocb_cpuctl.cpu_command = CFE_CPU_CMD_START; xiocb.plist.xiocb_cpuctl.gp_val = gp; xiocb.plist.xiocb_cpuctl.sp_val = sp; xiocb.plist.xiocb_cpuctl.a1_val = a1; xiocb.plist.xiocb_cpuctl.start_addr = (long)fn; cfe_iocb_dispatch(&xiocb); return xiocb.xiocb_status; } void cfe_open_console() { cfe_console_handle = cfe_getstdhandle(CFE_STDHANDLE_CONSOLE); } void cfe_console_print(char *str) { if (cfe_console_handle != -1) { cfe_write(cfe_console_handle, str, strlen(str)); } } --- NEW FILE: cfe_api.h --- /* * Copyright (C) 2000, 2001 Broadcom Corporation * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License * as published by the Free Software Foundation; either version 2 * of the License, or (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ /* ********************************************************************* * Broadcom Common Firmware Environment (CFE) * * Device function prototypes File: cfe_api.h * * This module contains prototypes for cfe_devfuncs.c, a set * of wrapper routines to the IOCB interface. This file, * along with cfe_api.c, can be incorporated into programs * that need to call CFE. * * Author: Mitch Lichtenberg (mp...@br...) * ********************************************************************* */ #define CFE_EPTSEAL 0x43464531 #define CFE_APIENTRY 0x9FC00500 #define CFE_APISEAL 0x9FC00508 #ifndef __ASSEMBLER__ int cfe_init(cfe_xuint_t handle); int cfe_open(char *name); int cfe_close(int handle); int cfe_readblk(int handle,cfe_xint_t offset,unsigned char *buffer,int length); int cfe_read(int handle,unsigned char *buffer,int length); int cfe_writeblk(int handle,cfe_xint_t offset,unsigned char *buffer,int length); int cfe_write(int handle,unsigned char *buffer,int length); int cfe_ioctl(int handle,unsigned int ioctlnum,unsigned char *buffer,int length,int *retlen); int cfe_inpstat(int handle); int cfe_enumenv(int idx,char *name,int namelen,char *val,int vallen); int cfe_enummem(long idx, unsigned long *addr, unsigned long *size, long *type); int cfe_setenv(char *name,char *val); int cfe_getenv(char *name,char *dest,int destlen); long long cfe_getticks(void); int cfe_exit(int warm, int status); int cfe_flushcache(int flg); int cfe_getstdhandle(int flg); int cfe_start_cpu(int cpu, void (*fn)(void), long sp, long gp, long a1); void cfe_open_console(void); void cfe_console_print(char *); #endif --- NEW FILE: cfe_error.h --- /* * Copyright (C) 2000, 2001 Broadcom Corporation * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License * as published by the Free Software Foundation; either version 2 * of the License, or (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ /* ********************************************************************* * Broadcom Common Firmware Environment (CFE) * * Error codes File: cfe_error.h * * CFE's global error code list is here. * * Author: Mitch Lichtenberg (mp...@br...) * ********************************************************************* */ #define CFE_OK 0 #define CFE_ERR -1 /* generic error */ #define CFE_ERR_INV_COMMAND -2 #define CFE_ERR_EOF -3 #define CFE_ERR_IOERR -4 #define CFE_ERR_NOMEM -5 #define CFE_ERR_DEVNOTFOUND -6 #define CFE_ERR_DEVOPEN -7 #define CFE_ERR_INV_PARAM -8 #define CFE_ERR_ENVNOTFOUND -9 #define CFE_ERR_ENVREADONLY -10 #define CFE_ERR_NOTELF -11 #define CFE_ERR_NOT32BIT -12 #define CFE_ERR_WRONGENDIAN -13 #define CFE_ERR_BADELFVERS -14 #define CFE_ERR_NOTMIPS -15 #define CFE_ERR_BADELFFMT -16 #define CFE_ERR_BADADDR -17 #define CFE_ERR_FILENOTFOUND -18 #define CFE_ERR_UNSUPPORTED -19 #define CFE_ERR_HOSTUNKNOWN -20 #define CFE_ERR_TIMEOUT -21 #define CFE_ERR_PROTOCOLERR -22 #define CFE_ERR_NETDOWN -23 #define CFE_ERR_NONAMESERVER -24 #define CFE_ERR_NOHANDLES -25 #define CFE_ERR_ALREADYBOUND -26 #define CFE_ERR_CANNOTSET -27 #define CFE_ERR_NOMORE -28 #define CFE_ERR_BADFILESYS -29 #define CFE_ERR_FSNOTAVAIL -30 #define CFE_ERR_INVBOOTBLOCK -31 #define CFE_ERR_WRONGDEVTYPE -32 #define CFE_ERR_BBCHECKSUM -33 #define CFE_ERR_BOOTPROGCHKSUM -34 --- NEW FILE: cfe_xiocb.h --- /* * Copyright (C) 2000, 2001 Broadcom Corporation * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License * as published by the Free Software Foundation; either version 2 * of the License, or (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ /* ********************************************************************* * Broadcom Common Firmware Environment (CFE) * * IOCB definitions File: cfe_iocb.h * * This module describes CFE's IOCB structure, the main * data structure used to communicate API requests with CFE. * * Author: Mitch Lichtenberg (mp...@br...) * ********************************************************************* */ /* ********************************************************************* * Constants ********************************************************************* */ #define CFE_CMD_FW_GETINFO 0 #define CFE_CMD_FW_RESTART 1 #define CFE_CMD_FW_BOOT 2 #define CFE_CMD_FW_CPUCTL 3 #define CFE_CMD_FW_GETTIME 4 #define CFE_CMD_FW_MEMENUM 5 #define CFE_CMD_FW_FLUSHCACHE 6 #define CFE_CMD_DEV_GETHANDLE 9 #define CFE_CMD_DEV_ENUM 10 #define CFE_CMD_DEV_OPEN 11 #define CFE_CMD_DEV_INPSTAT 12 #define CFE_CMD_DEV_READ 13 #define CFE_CMD_DEV_WRITE 14 #define CFE_CMD_DEV_IOCTL 15 #define CFE_CMD_DEV_CLOSE 16 #define CFE_CMD_DEV_GETINFO 17 #define CFE_CMD_ENV_ENUM 20 #define CFE_CMD_ENV_GET 22 #define CFE_CMD_ENV_SET 23 #define CFE_CMD_ENV_DEL 24 #define CFE_CMD_MAX 32 #define CFE_MI_RESERVED 0 /* memory is reserved, do not use */ #define CFE_MI_AVAILABLE 1 /* memory is available */ #define CFE_FLG_WARMSTART 0x00000001 #define CFE_FLG_ENV_PERMANENT 0x00000001 #define CFE_CPU_CMD_START 1 #define CFE_CPU_CMD_STOP 0 #define CFE_STDHANDLE_CONSOLE 0 #define CFE_DEV_NETWORK 1 #define CFE_DEV_DISK 2 #define CFE_DEV_FLASH 3 #define CFE_DEV_SERIAL 4 #define CFE_DEV_CPU 5 #define CFE_DEV_NVRAM 6 #define CFE_DEV_OTHER 7 #define CFE_DEV_MASK 0x0F #define CFE_CACHE_FLUSH_D 1 #define CFE_CACHE_INVAL_I 2 #define CFE_CACHE_INVAL_D 4 #define CFE_CACHE_INVAL_L2 8 /* ********************************************************************* * Structures ********************************************************************* */ typedef unsigned long long cfe_xuint_t; typedef long long cfe_xint_t; typedef long long cfe_xptr_t; typedef struct xiocb_buffer_s { cfe_xuint_t buf_offset; /* offset on device (bytes) */ cfe_xptr_t buf_ptr; /* pointer to a buffer */ cfe_xuint_t buf_length; /* length of this buffer */ cfe_xuint_t buf_retlen; /* returned length (for read ops) */ cfe_xuint_t buf_ioctlcmd; /* IOCTL command (used only for IOCTLs) */ } xiocb_buffer_t; #define buf_devflags buf_ioctlcmd /* returned device info flags */ typedef struct xiocb_inpstat_s { cfe_xuint_t inp_status; /* 1 means input available */ } xiocb_inpstat_t; typedef struct xiocb_envbuf_s { cfe_xint_t enum_idx; /* 0-based enumeration index */ cfe_xptr_t name_ptr; /* name string buffer */ cfe_xint_t name_length; /* size of name buffer */ cfe_xptr_t val_ptr; /* value string buffer */ cfe_xint_t val_length; /* size of value string buffer */ } xiocb_envbuf_t; typedef struct xiocb_cpuctl_s { cfe_xuint_t cpu_number; /* cpu number to control */ cfe_xuint_t cpu_command; /* command to issue to CPU */ cfe_xuint_t start_addr; /* CPU start address */ cfe_xuint_t gp_val; /* starting GP value */ cfe_xuint_t sp_val; /* starting SP value */ cfe_xuint_t a1_val; /* starting A1 value */ } xiocb_cpuctl_t; typedef struct xiocb_time_s { cfe_xint_t ticks; /* current time in ticks */ } xiocb_time_t; typedef struct xiocb_exitstat_s { cfe_xint_t status; } xiocb_exitstat_t; typedef struct xiocb_meminfo_s { cfe_xint_t mi_idx; /* 0-based enumeration index */ cfe_xint_t mi_type; /* type of memory block */ cfe_xuint_t mi_addr; /* physical start address */ cfe_xuint_t mi_size; /* block size */ } xiocb_meminfo_t; #define CFE_FWI_64BIT 0x00000001 #define CFE_FWI_32BIT 0x00000002 #define CFE_FWI_RELOC 0x00000004 #define CFE_FWI_UNCACHED 0x00000008 #define CFE_FWI_MULTICPU 0x00000010 #define CFE_FWI_FUNCSIM 0x00000020 #define CFE_FWI_RTLSIM 0x00000040 typedef struct xiocb_fwinfo_s { cfe_xint_t fwi_version; /* major, minor, eco version */ cfe_xint_t fwi_totalmem; /* total installed mem */ cfe_xint_t fwi_flags; /* various flags */ cfe_xint_t fwi_boardid; /* board ID */ cfe_xint_t fwi_bootarea_va; /* VA of boot area */ cfe_xint_t fwi_bootarea_pa; /* PA of boot area */ cfe_xint_t fwi_bootarea_size; /* size of boot area */ cfe_xint_t fwi_reserved1; cfe_xint_t fwi_reserved2; cfe_xint_t fwi_reserved3; } xiocb_fwinfo_t,cfe_fwinfo_t; typedef struct cfe_xiocb_s { cfe_xuint_t xiocb_fcode; /* IOCB function code */ cfe_xint_t xiocb_status; /* return status */ cfe_xint_t xiocb_handle; /* file/device handle */ cfe_xuint_t xiocb_flags; /* flags for this IOCB */ cfe_xuint_t xiocb_psize; /* size of parameter list */ union { xiocb_buffer_t xiocb_buffer; /* buffer parameters */ xiocb_inpstat_t xiocb_inpstat; /* input status parameters */ xiocb_envbuf_t xiocb_envbuf; /* environment function parameters */ xiocb_cpuctl_t xiocb_cpuctl; /* CPU control parameters */ xiocb_time_t xiocb_time; /* timer parameters */ xiocb_meminfo_t xiocb_meminfo; /* memory arena info parameters */ xiocb_fwinfo_t xiocb_fwinfo; /* firmware information */ xiocb_exitstat_t xiocb_exitstat; /* Exit status */ } plist; } cfe_xiocb_t; --- NEW FILE: cmdline.c --- /* * Copyright (C) 2000, 2001 Broadcom Corporation * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License * as published by the Free Software Foundation; either version 2 * of the License, or (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ #include <asm/bootinfo.h> /* * The naming of this variable is a remnant of the initial mips port to ARC-firmware * based SGI consoles. We don't really need to do anything for the variable other * than provide an instantiation. Everything about arcs_cmdline seems more than a * little bit hackish... */ char arcs_cmdline[COMMAND_LINE_SIZE]; --- NEW FILE: memory.c --- /* * Copyright (C) 2000, 2001 Broadcom Corporation * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License * as published by the Free Software Foundation; either version 2 * of the License, or (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ /* * Memory related routines */ #include <asm/page.h> #include <linux/autoconf.h> extern long swarm_mem_region_addrs[]; extern long swarm_mem_region_sizes[]; extern unsigned int swarm_mem_region_count; int page_is_ram(unsigned long pagenr) { unsigned long addr = pagenr << PAGE_SHIFT; #ifdef CONFIG_SWARM_STANDALONE if (addr < (CONFIG_SIBYTE_SWARM_RAM_SIZE * 1024 * 1024)) { return 1; } #else int i; for (i = 0; i < swarm_mem_region_count; i++) { if ((addr >= swarm_mem_region_addrs[i]) && (addr < (swarm_mem_region_addrs[i] + swarm_mem_region_sizes[i]))) { return 1; } } #endif return 0; } --- NEW FILE: rtc.c --- /* * Copyright (C) 2000, 2001 Broadcom Corporation * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License * as published by the Free Software Foundation; either version 2 * of the License, or (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ /* * Not really sure what is supposed to be here, yet */ #include <linux/spinlock.h> #include <linux/mc146818rtc.h> static unsigned char swarm_rtc_read_data(unsigned long addr) { return 0; } static void swarm_rtc_write_data(unsigned char data, unsigned long addr) { } static int swarm_rtc_bcd_mode(void) { return 0; } struct rtc_ops swarm_rtc_ops = { &swarm_rtc_read_data, &swarm_rtc_write_data, &swarm_rtc_bcd_mode }; --- NEW FILE: setup.c --- /* * Copyright (C) 2000, 2001 Broadcom Corporation * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License * as published by the Free Software Foundation; either version 2 * of the License, or (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ /* * Setup code for the SWARM board */ #include <linux/spinlock.h> #include <linux/mc146818rtc.h> #include <linux/mm.h> #include <linux/bootmem.h> #include <linux/blk.h> #include <asm/irq.h> #include <asm/bootinfo.h> #include <asm/addrspace.h> #include <asm/sibyte/swarm.h> #include <asm/sibyte/sb1250.h> #include <asm/sibyte/sb1250_defs.h> #include <asm/sibyte/sb1250_regs.h> #include <asm/reboot.h> #include <linux/ide.h> #include "cfe_xiocb.h" #include "cfe_api.h" #include "cfe_error.h" extern struct rtc_ops swarm_rtc_ops; extern int cfe_console_handle; #ifdef CONFIG_BLK_DEV_IDE_SWARM struct ide_ops *ide_ops; #endif #ifdef CONFIG_L3DEMO extern void *l3info; #endif /* Max ram addressable in 32-bit segments */ #define MAX_RAM_SIZE (1024*1024*256) #ifndef CONFIG_SWARM_STANDALONE long swarm_mem_region_addrs[CONFIG_SIBYTE_SWARM_MAX_MEM_REGIONS]; long swarm_mem_region_sizes[CONFIG_SIBYTE_SWARM_MAX_MEM_REGIONS]; unsigned int swarm_mem_region_count; #endif #ifdef CONFIG_BLK_DEV_IDE_SWARM static int swarm_ide_default_irq(ide_ioreg_t base) { return 0; } static ide_ioreg_t swarm_ide_default_io_base(int index) { return 0; } static void swarm_ide_init_hwif_ports (hw_regs_t *hw, ide_ioreg_t data_port, ide_ioreg_t ctrl_port, int *irq) { ide_ioreg_t reg = data_port; int i; for (i = IDE_DATA_OFFSET; i <= IDE_STATUS_OFFSET; i++) { hw->io_ports[i] = reg; reg += 1; } if (ctrl_port) { hw->io_ports[IDE_CONTROL_OFFSET] = ctrl_port; } else { hw->io_ports[IDE_CONTROL_OFFSET] = hw->io_ports[IDE_DATA_OFFSET] + 0x206; } if (irq != NULL) *irq = 0; hw->io_ports[IDE_IRQ_OFFSET] = 0; } static int swarm_ide_request_irq(unsigned int irq, void (*handler)(int,void *, struct pt_regs *), unsigned long flags, const char *device, void *dev_id) { return request_irq(irq, handler, flags, device, dev_id); } static void swarm_ide_free_irq(unsigned int irq, void *dev_id) { free_irq(irq, dev_id); } static int swarm_ide_check_region(ide_ioreg_t from, unsigned int extent) { /* Note: "check_region" and friends do conflict management on ISA I/O space. Our disk is not in that space, so this check won't work */ /* return check_region(from, extent); */ return 0; } static void swarm_ide_request_region(ide_ioreg_t from, unsigned int extent, const char *name) { /* request_region(from, extent, name); */ } static void swarm_ide_release_region(ide_ioreg_t from, unsigned int extent) { /* release_region(from, extent); */ } struct ide_ops swarm_ide_ops = { &swarm_ide_default_irq, &swarm_ide_default_io_base, &swarm_ide_init_hwif_ports, &swarm_ide_request_irq, &swarm_ide_free_irq, &swarm_ide_check_region, &swarm_ide_request_region, &swarm_ide_release_region }; #endif static void stop_this_cpu(void *dummy) { printk("Cpu %d stopping\n", smp_processor_id()); for (;;); } static void smp_cpu0_exit(void) { printk("cpu %d poked\n", smp_processor_id()); /* XXXKW we are in the mailbox handler... */ __asm__(".set push\n\t" ".set mips32\n\t" "la $2, swarm_linux_exit\n\t" "mtc0 $2, $24\n\t" "eret\n\t" ".set pop" ::: "$2"); } extern void (*smp_cpu0_finalize)(void); static void swarm_linux_exit(void) { if (smp_processor_id()) { /* Make cpu 0 do the swarm_linux_exit */ /* XXXKW this isn't quite there yet */ smp_cpu0_finalize = smp_cpu0_exit; stop_this_cpu(NULL); } else { printk("swarm_linux_exit called...passing control back to CFE\n"); cfe_exit(1, 0); printk("cfe_exit returned??\n"); while(1); } } extern unsigned long mips_io_port_base; void __init swarm_setup(void) { extern int panic_timeout; rtc_ops = &swarm_rtc_ops; panic_timeout = 5; /* For debug. This should probably be raised later */ _machine_restart = (void (*)(char *))swarm_linux_exit; _machine_halt = swarm_linux_exit; _machine_power_off = swarm_linux_exit; #ifdef CONFIG_L3DEMO if (l3info != NULL) { printk("\n"); } #endif printk("This kernel optimized for " #ifdef CONFIG_SIMULATION "simulation" #else "board" #endif " runs\n"); #ifdef CONFIG_BLK_DEV_IDE_SWARM ide_ops = &swarm_ide_ops; #endif } /* This is the kernel command line. Actually, it's copied, eventually, to command_line, and looks to be quite redundant. But not something to fix just now */ extern char arcs_cmdline[]; #ifdef CONFIG_EMBEDDED_RAMDISK /* These are symbols defined by the ramdisk linker script */ extern unsigned char __rd_start; extern unsigned char __rd_end; #endif static void prom_meminit(void) { #ifndef CONFIG_SWARM_STANDALONE unsigned long addr, size; long type; unsigned int idx; int rd_flag; #endif #ifdef CONFIG_BLK_DEV_INITRD unsigned long initrd_pstart; unsigned long initrd_pend; #ifdef CONFIG_EMBEDDED_RAMDISK /* If we're using an embedded ramdisk, then __rd_start and __rd_end are defined by the linker to be on either side of the ramdisk area. Otherwise, initrd_start should be defined by kernel command line arguments */ if (initrd_start == 0) { initrd_start = (unsigned long)&__rd_start; initrd_end = (unsigned long)&__rd_end; } #endif initrd_pstart = __pa(initrd_start); initrd_pend = __pa(initrd_end); if (initrd_start && ((initrd_pstart > MAX_RAM_SIZE) || (initrd_pend > MAX_RAM_SIZE))) { setleds("INRD"); panic("initrd out of addressable memory\n"); } #endif /* INITRD */ #ifdef CONFIG_SWARM_STANDALONE /* Standalone compile, memory is hardcoded */ if (initrd_start) { add_memory_region(0, initrd_pstart, BOOT_MEM_RAM); add_memory_region(initrd_pstart, initrd_pend-initrd_pstart, BOOT_MEM_RESERVED); add_memory_region(initrd_pend, (CONFIG_SIBYTE_SWARM_RAM_SIZE * 1024 * 1024)-initrd_pend, BOOT_MEM_RAM); } else { add_memory_region(0, CONFIG_SIBYTE_SWARM_RAM_SIZE * 1024 * 1024, BOOT_MEM_RAM); } #else /* Run with the firmware */ for (idx = 0; cfe_enummem(idx, &addr, &size, &type) != CFE_ERR_NOMORE; idx++) { rd_flag = 0; if (type == CFE_MI_AVAILABLE) { /* See if this block contains (any portion of) the ramdisk */ #ifdef CONFIG_BLK_DEV_INITRD if (initrd_start) { if ((initrd_pstart > addr) && (initrd_pstart < (addr + size))) { add_memory_region(addr, initrd_pstart-addr, BOOT_MEM_RAM); rd_flag = 1; } if ((initrd_pend > addr) && (initrd_pend < (addr + size))) { add_memory_region(initrd_pend, (addr + size)-initrd_pend, BOOT_MEM_RAM); rd_flag = 1; } } #endif if (!rd_flag) { if (addr < MAX_RAM_SIZE) { if (size > MAX_RAM_SIZE) { size = MAX_RAM_SIZE - addr; } add_memory_region(addr, size, BOOT_MEM_RAM); } } swarm_mem_region_addrs[swarm_mem_region_count] = addr; swarm_mem_region_sizes[swarm_mem_region_count] = size; swarm_mem_region_count++; if (swarm_mem_region_count == CONFIG_SIBYTE_SWARM_MAX_MEM_REGIONS) { while(1); /* Too many regions. Need to configure more */ } } } #ifdef CONFIG_BLK_DEV_INITRD if (initrd_start) { add_memory_region(initrd_pstart, initrd_pend-initrd_pstart, BOOT_MEM_RESERVED); } #endif #endif /* CONFIG_SWARM_STANDALONE */ } #ifdef CONFIG_BLK_DEV_INITRD static int __init initrd_setup(char *str) { /* *Initrd location comes in the form "<hex size of ramdisk in bytes>@<location in memory>" * e.g. initrd=3abfd@80010000. This is set up by the loader. */ char *tmp, *endptr; unsigned long initrd_size; for (tmp = str; *tmp != '@'; tmp++) { if (!*tmp) { goto fail; } } *tmp = 0; tmp++; if (!*tmp) { goto fail; } initrd_size = simple_strtol(str, &endptr, 16); if (*endptr) { goto fail; } initrd_start = simple_strtol(tmp, &endptr, 16); if (*endptr) { goto fail; } initrd_end = initrd_start + initrd_size; printk("Found initrd of %lx@%lx\n", initrd_size, initrd_start); return 1; fail: printk("Bad initrd argument. Disabling initrd\n"); initrd_start = 0; initrd_end = 0; return 1; } #endif /* prom_init is called just after the cpu type is determined, from init_arch() */ int prom_init(int argc, char **argv, char **envp, int *prom_vec) { #ifdef CONFIG_SWARM_STANDALONE strcpy(arcs_cmdline, "root=/dev/ram0 "); #else /* * This should go away. Detect if we're booting * straight from cfe without a loader. If we * are, then we've got a prom vector in a0. Otherwise, * argc (and argv and envp, for that matter) will be 0) */ if (argc < 0) { prom_vec = (int *)argc; } cfe_init((long)prom_vec); cfe_open_console(); if (cfe_getenv("LINUX_CMDLINE", arcs_cmdline, COMMAND_LINE_SIZE) < 0) { if (argc < 0) { /* It's OK for direct boot to not provide a command line */ strcpy(arcs_cmdline, "root=/dev/ram0 "); } else { /* The loader should have set the command line */ setleds("CMDL"); panic("LINUX_CMDLINE not defined in cfe."); } } #ifdef CONFIG_BLK_DEV_INITRD { char *ptr; /* Need to find out early whether we've got an initrd. So scan the list looking now */ for (ptr = arcs_cmdline; *ptr; ptr++) { while (*ptr == ' ') { ptr++; } if (!strncmp(ptr, "initrd=", 7)) { initrd_setup(ptr+7); break; } else { while (*ptr && (*ptr != ' ')) { ptr++; } } } } #endif /* CONFIG_BLK_DEV_INITRD */ #endif /* CONFIG_SWARM_STANDALONE */ /* Not sure this is needed, but it's the safe way. */ arcs_cmdline[COMMAND_LINE_SIZE-1] = 0; mips_machgroup = MACH_GROUP_SIBYTE; #if 0 #ifndef CONFIG_SWARM_STANDALONE for (i = 0; (i < argc) && (cmdline_idx < COMMAND_LINE_SIZE); i++) { if (!strncmp(argv[i], "initrd=", 7)) { /* Handle initrd argument early; we need to know about them for the memory map */ unsigned char *size_str = argv[i] + 7; unsigned char *loc_str = size_str; unsigned long size, loc; while (*loc_str && (*loc_str != '@')) { loc_str++; } if (!*loc_str) { printk("Ignoring malformed initrd argument: %s\n", argv[i]); continue; } *loc_str = '\0'; loc_str++; size = simple_strtoul(size_str, NULL, 16); loc = simple_strtoul(loc_str, NULL, 16); if (size && loc) { printk("Found initrd argument: 0x%lx@0x%lx\n", size, loc); initrd_start = loc; initrd_end = (loc + size + PAGE_SIZE - 1) & PAGE_MASK; } } else { if ((strlen(argv[i]) + cmdline_idx + 1) > COMMAND_LINE_SIZE) { printk("Command line too long. Cut these:\n"); for (; i < argc; i++) { printk(" %s\n", argv[i]); } } else { strcpy(arcs_cmdline + cmdline_idx, argv[i]); } } } #endif #endif prom_meminit(); return 0; } /* Not sure what I'm supposed to do here. Nothing, I think */ void prom_free_prom_memory(void) { } static void setled(unsigned int index, char c) { volatile unsigned char *led_ptr = (unsigned char *)(IO_SPACE_BASE | LED_BASE_ADDR); if (index < 4) { led_ptr[(3-index)<<3] = c; } } void setleds(char *str) { int i; for (i = 0; i < 4; i++) { if (!str[i]) { for (; i < 4; i++) { setled(' ', str[i]); } } else { setled(i, str[i]); } } } #include <linux/timer.h> static struct timer_list led_timer; /* #ifdef CONFIG_SMP static unsigned char led_msg[] = "CSWARM...now in glorious SMP! "; #else static unsigned char led_msg[] = "CSWARM Lives!!! "; #endif */ static unsigned char default_led_msg[] = "Today: the CSWARM. Tomorrow: the WORLD!!!! "; static unsigned char *led_msg = default_led_msg; static unsigned char *led_msg_ptr = default_led_msg; void set_led_msg(char *new_msg) { led_msg = new_msg; led_msg_ptr = new_msg; setleds(" "); } static void move_leds(unsigned long arg) { int i; unsigned char *tmp = led_msg_ptr; for (i = 0; i < 4; i++) { setled(i, *tmp); tmp++; if (!*tmp) { tmp = led_msg; } } led_msg_ptr++; if (!*led_msg_ptr) { led_msg_ptr = led_msg; } del_timer(&led_timer); led_timer.expires = jiffies + (HZ/8); add_timer(&led_timer); } void hack_leds(void) { init_timer(&led_timer); led_timer.expires = jiffies + (HZ/8); led_timer.data = 0; led_timer.function = move_leds; add_timer(&led_timer); } --- NEW FILE: smp.c --- /* * Copyright (C) 2001 Broadcom Corporation * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License * as published by the Free Software Foundation; either version 2 * of the License, or (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ #include <linux/config.h> #include <linux/kernel.h> #include <asm/sibyte/sb1250_regs.h> #include <asm/sibyte/sb1250_int.h> #include <asm/mipsregs.h> #include "cfe_xiocb.h" #include "cfe_api.h" extern void asmlinkage smp_bootstrap(void); /* Boot all other cpus in the system, initialize them, and bring them into the boot fn */ int prom_boot_secondary(int cpu, unsigned long sp, unsigned long gp) { int retval; if ((retval = cfe_start_cpu(1, &smp_bootstrap, sp, gp, 0)) != 0) { printk("cfe_start_cpu returned %i\n" , retval); panic ("secondary bootstrap failed\n"); } return 1; } void prom_init_secondary(void) { /* Set up kseg0 to be cachable coherent */ clear_cp0_config(CONF_CM_CMASK); set_cp0_config(0x5); /* Enable interrupts for lines 0-4 */ clear_cp0_status(0xe000); set_cp0_status(0x1f01); } /* * Set up state, return the total number of cpus in the system, including * the master */ int prom_setup_smp(void) { /* Nothing to do here */ return 2; } void prom_smp_finish(void) { sb1250_smp_finish(); } --- NEW FILE: time.c --- /* * Copyright (C) 2000, 2001 Broadcom Corporation * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License * as published by the Free Software Foundation; either version 2 * of the License, or (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ /* * Time routines for the swarm board. We pass all the hard stuff * through to the sb1250 handling code. Only thing we really keep * track of here is what time of day we think it is. And we don't * really even do a good job of that... */ #include <linux/init.h> #include <linux/time.h> #include <linux/sched.h> #include <linux/spinlock.h> #include <asm/system.h> #include <asm/addrspace.h> #include <asm/sibyte/64bit.h> #include <asm/sibyte/sb1250.h> #include <asm/sibyte/sb1250_regs.h> #include <asm/sibyte/sb1250_smbus.h> static unsigned long long sec_bias = 0; static unsigned int usec_bias = 0; extern rwlock_t xtime_lock; /* Xicor 1241 definitions */ /* * Register bits */ #define X1241REG_SR_BAT 0x80 /* currently on battery power */ #define X1241REG_SR_RWEL 0x04 /* r/w latch is enabled, can write RTC */ #define X1241REG_SR_WEL 0x02 /* r/w latch is unlocked, can enable r/w now */ #define X1241REG_SR_RTCF 0x01 /* clock failed */ #define X1241REG_BL_BP2 0x80 /* block protect 2 */ #define X1241REG_BL_BP1 0x40 /* block protect 1 */ #define X1241REG_BL_BP0 0x20 /* block protect 0 */ #define X1241REG_BL_WD1 0x10 #define X1241REG_BL_WD0 0x08 #define X1241REG_HR_MIL 0x80 /* military time format */ /* * Register numbers */ #define X1241REG_BL 0x10 /* block protect bits */ #define X1241REG_INT 0x11 /* */ #define X1241REG_SC 0x30 /* Seconds */ #define X1241REG_MN 0x31 /* Minutes */ #define X1241REG_HR 0x32 /* Hours */ #define X1241REG_DT 0x33 /* Day of month */ #define X1241REG_MO 0x34 /* Month */ #define X1241REG_YR 0x35 /* Year */ #define X1241REG_DW 0x36 /* Day of Week */ #define X1241REG_Y2K 0x37 /* Year 2K */ #define X1241REG_SR 0x3F /* Status register */ #define X1241_CCR_ADDRESS 0x6F #define SMB_CSR(reg) (KSEG1 | A_SMB_REGISTER(1, reg)) static int xicor_read(uint8_t addr) { while (in64(SMB_CSR(R_SMB_STATUS)) & M_SMB_BUSY) ; out64((addr >> 8) & 0x7, SMB_CSR(R_SMB_CMD)); out64((addr & 0xff), SMB_CSR(R_SMB_DATA)); out64((V_SMB_ADDR(X1241_CCR_ADDRESS) | V_SMB_TT_WR2BYTE), SMB_CSR(R_SMB_START)); while (in64(SMB_CSR(R_SMB_STATUS)) & M_SMB_BUSY) ; out64((V_SMB_ADDR(X1241_CCR_ADDRESS) | V_SMB_TT_RD1BYTE), SMB_CSR(R_SMB_START)); while (in64(SMB_CSR(R_SMB_STATUS)) & M_SMB_BUSY) ; if (in64(SMB_CSR(R_SMB_STATUS)) & M_SMB_ERROR) { /* Clear error bit by writing a 1 */ out64(M_SMB_ERROR, SMB_CSR(R_SMB_STATUS)); return -1; } return (in64(SMB_CSR(R_SMB_DATA)) & 0xff); } static int xicor_write(uint8_t addr, int b) { while (in64(SMB_CSR(R_SMB_STATUS)) & M_SMB_BUSY) ; out64(addr, SMB_CSR(R_SMB_CMD)); out64((addr & 0xff) | ((b & 0xff) << 8), SMB_CSR(R_SMB_DATA)); out64(V_SMB_ADDR(X1241_CCR_ADDRESS) | V_SMB_TT_WR3BYTE, SMB_CSR(R_SMB_START)); while (in64(SMB_CSR(R_SMB_STATUS)) & M_SMB_BUSY) ; if (in64(SMB_CSR(R_SMB_STATUS)) & M_SMB_ERROR) { /* Clear error bit by writing a 1 */ out64(M_SMB_ERROR, SMB_CSR(R_SMB_STATUS)); return -1; } else { return 0; } } #define BCD_TO_BIN(val) ((val)=((val)&15) + ((val)>>4)*10) #define BIN_TO_BCD(val) ((val)=(((val)/10)<<4) + (val)%10) /* * In order to set the CMOS clock precisely, set_rtc_mmss has to be * called 500 ms after the second nowtime has started, because when * nowtime is written into the registers of the CMOS clock, it will * jump to the next second precisely 500 ms later. Check the Motorola * MC146818A or Dallas DS12887 data sheet for details. * * BUG: This routine does not handle hour overflow properly; it just * sets the minutes. Usually you'll only notice that after reboot! */ int set_rtc_mmss(unsigned long nowtime) { int retval = 0; int real_seconds, real_minutes, cmos_minutes; cmos_minutes = xicor_read(X1241REG_MN); BCD_TO_BIN(cmos_minutes); /* * since we're only adjusting minutes and seconds, * don't interfere with hour overflow. This avoids * messing with unknown time zones but requires your * RTC not to be off by more than 15 minutes */ real_seconds = nowtime % 60; real_minutes = nowtime / 60; if (((abs(real_minutes - cmos_minutes) + 15)/30) & 1) real_minutes += 30; /* correct for half hour time zone */ real_minutes %= 60; /* unlock writes to the CCR */ xicor_write(X1241REG_SR, X1241REG_SR_WEL); xicor_write(X1241REG_SR, X1241REG_SR_WEL | X1241REG_SR_RWEL); if (abs(real_minutes - cmos_minutes) < 30) { BIN_TO_BCD(real_seconds); BIN_TO_BCD(real_minutes); xicor_write(X1241REG_SC, real_seconds); xicor_write(X1241REG_MN, real_minutes); } else { printk(KERN_WARNING "set_rtc_mmss: can't update from %d to %d\n", cmos_minutes, real_minutes); retval = -1; } xicor_write(X1241REG_SR, 0); printk("set_rtc_mmss: %02d:%02d\n", real_minutes, real_seconds); return retval; } static unsigned long __init get_swarm_time(void) { unsigned int year, mon, day, hour, min, sec, y2k; sec = xicor_read(X1241REG_SC); min = xicor_read(X1241REG_MN); hour = xicor_read(X1241REG_HR); if (hour & X1241REG_HR_MIL) { hour &= 0x3f; } else { if (hour & 0x20) hour = (hour & 0xf) + 0x12; } BCD_TO_BIN(sec); BCD_TO_BIN(min); BCD_TO_BIN(hour); day = xicor_read(X1241REG_DT); mon = xicor_read(X1241REG_MO); year = xicor_read(X1241REG_YR); y2k = xicor_read(X1241REG_Y2K); BCD_TO_BIN(day); BCD_TO_BIN(mon); BCD_TO_BIN(year); BCD_TO_BIN(y2k); year += (y2k * 100); return mktime(year, mon, day, hour, min, sec); } /* * Bring up the timer at 100 Hz. */ void __init time_init(void) { unsigned int flags; int status; /* Set up the scd general purpose timer 0 to cpu 0 */ sb1250_time_init(); /* Establish communication with the Xicor 1241 RTC */ /* XXXKW how do I share the SMBus with the I2C subsystem? */ out64(K_SMB_FREQ_400KHZ, SMB_CSR(R_SMB_FREQ)); out64(0, SMB_CSR(R_SMB_CONTROL)); if ((status = xicor_read(X1241REG_SR_RTCF)) < 0) { printk("x1241: couldn't detect on SWARM SMBus 1\n"); } else { if (status & X1241REG_SR_RTCF) printk("x1241: battery failed -- time is probably wrong\n"); write_lock_irqsave (&xtime_lock, flags); xtime.tv_sec = get_swarm_time(); xtime.tv_usec = 0; write_unlock_irqrestore(&xtime_lock, flags); } } void do_settimeofday(struct timeval *tv) { unsigned long saved_jiffies; unsigned long flags; saved_jiffies = jiffies; write_lock_irqsave(&xtime_lock, flags); sec_bias = (saved_jiffies/HZ) - tv->tv_sec; usec_bias = ((saved_jiffies%HZ)*(1000000/HZ)) - tv->tv_usec; write_unlock_irqrestore(&xtime_lock, flags); } void do_gettimeofday(struct timeval *tv) { unsigned long saved_jiffies; unsigned long flags; saved_jiffies = jiffies; read_lock_irqsave(&xtime_lock, flags); tv->tv_sec = sec_bias + (saved_jiffies/HZ); tv->tv_usec = usec_bias + ((saved_jiffies%HZ) * (1000000/HZ)); read_unlock_irqrestore(&xtime_lock, flags); } |