diff options
author | Sebastian Huber <sebastian.huber@embedded-brains.de> | 2018-04-25 10:25:00 +0200 |
---|---|---|
committer | Sebastian Huber <sebastian.huber@embedded-brains.de> | 2018-04-25 10:30:30 +0200 |
commit | 8266fb53f9c1c19768314e77a91792f3f55312ab (patch) | |
tree | c815c760fbc723ca7b98c81f469a2a427637e460 /bsps/powerpc/beatnik | |
parent | bsp/mvme3100: Move flashcfg.c to bsps (diff) | |
download | rtems-8266fb53f9c1c19768314e77a91792f3f55312ab.tar.bz2 |
bsp/beatnik: Move source files to bsps
This patch is a part of the BSP source reorganization.
Update #3285.
Diffstat (limited to 'bsps/powerpc/beatnik')
-rw-r--r-- | bsps/powerpc/beatnik/flash/flashcfg.c | 182 | ||||
-rw-r--r-- | bsps/powerpc/beatnik/marvell/discovery.c | 150 | ||||
-rw-r--r-- | bsps/powerpc/beatnik/marvell/gt.c | 1010 | ||||
-rw-r--r-- | bsps/powerpc/beatnik/marvell/gt_timer.c | 410 | ||||
-rw-r--r-- | bsps/powerpc/beatnik/marvell/gti2c.c | 447 | ||||
-rw-r--r-- | bsps/powerpc/beatnik/vme/vme_dma.c | 215 | ||||
-rw-r--r-- | bsps/powerpc/beatnik/vme/vmeconfig.c | 303 |
7 files changed, 2717 insertions, 0 deletions
diff --git a/bsps/powerpc/beatnik/flash/flashcfg.c b/bsps/powerpc/beatnik/flash/flashcfg.c new file mode 100644 index 0000000000..b5ba08f334 --- /dev/null +++ b/bsps/powerpc/beatnik/flash/flashcfg.c @@ -0,0 +1,182 @@ +/* + * Authorship + * ---------- + * This software ('beatnik' RTEMS BSP for MVME6100 and MVME5500) was + * created by Till Straumann <strauman@slac.stanford.edu>, 2005-2007, + * Stanford Linear Accelerator Center, Stanford University. + * + * Acknowledgement of sponsorship + * ------------------------------ + * The 'beatnik' BSP was produced by + * the Stanford Linear Accelerator Center, Stanford University, + * under Contract DE-AC03-76SFO0515 with the Department of Energy. + * + * Government disclaimer of liability + * ---------------------------------- + * Neither the United States nor the United States Department of Energy, + * nor any of their employees, makes any warranty, express or implied, or + * assumes any legal liability or responsibility for the accuracy, + * completeness, or usefulness of any data, apparatus, product, or process + * disclosed, or represents that its use would not infringe privately owned + * rights. + * + * Stanford disclaimer of liability + * -------------------------------- + * Stanford University makes no representations or warranties, express or + * implied, nor assumes any liability for the use of this software. + * + * Stanford disclaimer of copyright + * -------------------------------- + * Stanford University, owner of the copyright, hereby disclaims its + * copyright and all other rights in this software. Hence, anyone may + * freely use it for any purpose without restriction. + * + * Maintenance of notices + * ---------------------- + * In the interest of clarity regarding the origin and status of this + * SLAC software, this and all the preceding Stanford University notices + * are to remain affixed to any copy or derivative of this software made + * or distributed by the recipient and are to be affixed to any copy of + * software made or distributed by the recipient that contains a copy or + * derivative of this software. + * + * ------------------ SLAC Software Notices, Set 4 OTT.002a, 2004 FEB 03 + */ + +#include <bsp.h> +#include <stdio.h> +#include <inttypes.h> + +#define STATIC static + +#include <bsp/flashPgmPvt.h> + +/* MVME Board Specifica; board status reg. 2 where write-enable is controlled... */ + +#define SYS_FLASHA_WP (1<<5) +#define SYS_FBOOTB_WP (1<<3) +#define SYS_FBA_WP_HDR (1<<2) +#define SYS_FBOOTB_WP_HDR (1<<1) + +#define SYS_STATUS_2_REG (1) + +/* Forward Declarations */ +STATIC struct bankdesc * +bankcheck(int bank, int quiet); + +static int +flash_wp(int bank, int enbl); + +STATIC uint32_t +read_us_timer(void); + +/* Global Variables */ + +/* motload memory map */ +static struct bankdesc mvme5500Flash[] = { + { 0, 2 }, /* first entry gives number of entries */ + { 0xf2000000, 0x08000000, 0x20000*2, 2, BSP_flash_vendor_intel, 0, 0, 0, }, + { 0xff800000, 0x00800000, 0x20000*2, 2, BSP_flash_vendor_intel, 0, 0, 0, }, +}; + +/* motload memory map */ +static struct bankdesc mvme6100Flash[] = { + { 0, 2 }, /* first entry gives number of entries */ + { 0xf4000000, 0x04000000, 0x20000*2, 2, BSP_flash_vendor_intel, 0, 0, 0, }, + { 0xf8000000, 0x04000000, 0x20000*2, 2, BSP_flash_vendor_intel, 0, 0, 0, }, +}; + +struct flash_bsp_ops BSP_flashBspOps = { + bankcheck : bankcheck, + flash_wp : flash_wp, + read_us_timer: read_us_timer, +}; + +/* set (enbl:1), clear (enbl:0) or query (enbl:-1) write protection + * + * RETURNS 0 on success, nonzero on error. + */ +static int +flash_wp(int bank, int enbl) +{ +BSP_BoardType b; +A8 p; +unsigned char hwp = 0, swp; + + /* validate 'bank' argument */ + if ( !bankcheck( bank, 0 ) ) + return -1; + + switch ( (b=BSP_getBoardType()) ) { + default: + fprintf(stderr,"Unknown board type %i\n",b); + return -1; + + case MVME5500: + /* bit enables both banks; no readback of jumper available */ + p = (A8)(BSP_MV64x60_DEV1_BASE + SYS_STATUS_2_REG); + swp = SYS_FLASHA_WP; + break; + + case MVME6100: + { + + p = (A8)(BSP_MV64x60_DEV1_BASE + SYS_STATUS_2_REG); + if ( 0 == bank ) { + hwp = SYS_FBA_WP_HDR; + swp = SYS_FLASHA_WP; + } else { + hwp = SYS_FBOOTB_WP_HDR; + swp = SYS_FBOOTB_WP; + } + if ( enbl && (*p & hwp) ) { + fprintf(stderr,"HW write protection enabled (jumper)\n"); + return -1; + } + } + break; + } + if ( -1 == enbl ) { + /* query */ + return *p & (swp | hwp); + } else { + if ( enbl ) { + *p |= swp; + } else { + *p &= ~swp; + } + } + return 0; +} + +/* Lookup bank description in table */ +STATIC struct bankdesc * +bankcheck(int bank, int quiet) +{ +struct bankdesc *b; + switch ( BSP_getBoardType() ) { + case MVME5500: b = mvme5500Flash; break; + case MVME6100: b = mvme6100Flash; break; + default: + fprintf(stderr,"Unknown/unsupported board type\n"); + return 0; + } + if ( bank >= b->size || bank < 0 ) { + if ( !quiet ) + fprintf(stderr,"Invalid flash bank #: %i; (too big)\n", bank); + return 0; + } + return b + bank + 1; +} + +STATIC uint32_t read_us_timer(void) +{ +uint32_t now, mhz; + + /* we burn cycles anyways... */ + mhz = BSP_bus_frequency/BSP_time_base_divisor/1000; + + asm volatile("mftb %0":"=r"(now)); + + return now/mhz; +} diff --git a/bsps/powerpc/beatnik/marvell/discovery.c b/bsps/powerpc/beatnik/marvell/discovery.c new file mode 100644 index 0000000000..1d84ac3a01 --- /dev/null +++ b/bsps/powerpc/beatnik/marvell/discovery.c @@ -0,0 +1,150 @@ +/* + * Acknowledgements: + * Valuable information was obtained from the following drivers + * netbsd: (C) Allegro Networks Inc; Wasabi Systems Inc. + * linux: (C) MontaVista, Software, Inc; Chris Zankel, Mark A. Greer. + * rtems: (C) Brookhaven National Laboratory; K. Feng + * but this implementation is original work by the author. + */ + +/* + * Authorship + * ---------- + * This software ('beatnik' RTEMS BSP for MVME6100 and MVME5500) was + * created by Till Straumann <strauman@slac.stanford.edu>, 2005-2007, + * Stanford Linear Accelerator Center, Stanford University. + * + * Acknowledgement of sponsorship + * ------------------------------ + * The 'beatnik' BSP was produced by + * the Stanford Linear Accelerator Center, Stanford University, + * under Contract DE-AC03-76SFO0515 with the Department of Energy. + * + * Government disclaimer of liability + * ---------------------------------- + * Neither the United States nor the United States Department of Energy, + * nor any of their employees, makes any warranty, express or implied, or + * assumes any legal liability or responsibility for the accuracy, + * completeness, or usefulness of any data, apparatus, product, or process + * disclosed, or represents that its use would not infringe privately owned + * rights. + * + * Stanford disclaimer of liability + * -------------------------------- + * Stanford University makes no representations or warranties, express or + * implied, nor assumes any liability for the use of this software. + * + * Stanford disclaimer of copyright + * -------------------------------- + * Stanford University, owner of the copyright, hereby disclaims its + * copyright and all other rights in this software. Hence, anyone may + * freely use it for any purpose without restriction. + * + * Maintenance of notices + * ---------------------- + * In the interest of clarity regarding the origin and status of this + * SLAC software, this and all the preceding Stanford University notices + * are to remain affixed to any copy or derivative of this software made + * or distributed by the recipient and are to be affixed to any copy of + * software made or distributed by the recipient that contains a copy or + * derivative of this software. + * + * ------------------ SLAC Software Notices, Set 4 OTT.002a, 2004 FEB 03 + */ + +#include <rtems.h> +#include <rtems/bspIo.h> +#include <bsp.h> +#include <bsp/gtreg.h> +#include <bsp/pci.h> +#include <stdint.h> + +#ifndef PCI_VENDOR_ID_MARVELL +#define PCI_VENDOR_ID_MARVELL 0x11ab +#endif + +#ifndef PCI_DEVICE_ID_MARVELL_GT64260 +#define PCI_DEVICE_ID_MARVELL_GT64260 0x6430 +#endif + +#ifndef PCI_DEVICE_ID_MARVELL_MV64360 +#define PCI_DEVICE_ID_MARVELL_MV64360 0x6460 +#endif + +#if 0 +#define MV64x60_PCI0_CONFIG_ADDR (BSP_MV64x60_BASE + 0xcf8) +#define MV64x60_PCI0_CONFIG_DATA (BSP_MV64x60_BASE + 0xcfc) + +/* read from bus/slot/fn 0/0/0 */ +static unsigned long +pci_early_config_read(int offset, int width) +{ + out_be32((uint32_t*) pci.pci_config_addr, + 0x80|(0<<8)|(PCI_DEVFN(0,0)<<16)|((offset&~3)<<24)); + switch (width) { + default: + case 1: + return in_8((uint8_t*)pci.pci_config_data + (offset&3)); + case 2: + return in_le16((uint16_t*)pci.pci_config_data + (offset&3)); + case 4: + return in_le32((uint32_t *)pci.pci_config_data + (offset&3)); + } +} +#endif + +DiscoveryVersion +BSP_getDiscoveryVersion(int assertion) +{ +static DiscoveryVersion rval = unknown; + + if ( unknown ==rval ) { + unsigned char dc; + unsigned short ds; + /* this must work before and after the call to BSP_pciInitialize() -- + * since the host bridge is at 0,0,0 it doesn't matter if the hosed + * access methods are installed or not (as a matter of fact this shouldn't + * matter for any device on hose 0) + */ +printk("config addr is %p\n", BSP_pci_configuration.pci_config_addr); +printk("config data is %p\n", BSP_pci_configuration.pci_config_data); + pci_read_config_word(0,0,0,PCI_VENDOR_ID, &ds); + if ( PCI_VENDOR_ID_MARVELL != ds ) { + if ( assertion ) { + printk("Host bridge vendor id: 0x%04x\n",ds); + rtems_panic("Host bridge vendor @ pci(0,0,0) is not MARVELL"); + } + else return unknown; + } + pci_read_config_word(0,0,0,PCI_DEVICE_ID, &ds); + pci_read_config_byte(0,0,0,PCI_REVISION_ID, &dc); + switch (ds) { + case PCI_DEVICE_ID_MARVELL_MV64360: + rval = MV_64360; + break; + + case PCI_DEVICE_ID_MARVELL_GT64260: + switch (dc) { + default: + break; + + case 0x10: + return (rval = GT_64260_A); + + case 0x20: + return (rval = GT_64260_B); + } + + default: + if ( assertion ) { + printk("Marvell device id 0x%04x, revision 0x%02x; check %s:%u\n", + ds, dc, + __FILE__,__LINE__); + rtems_panic("Unknown Marvell bridge or revision@ pci(0,0,0) is not MARVELL"); + } + break; + } + } + + return rval; +} diff --git a/bsps/powerpc/beatnik/marvell/gt.c b/bsps/powerpc/beatnik/marvell/gt.c new file mode 100644 index 0000000000..c71b7cbdb3 --- /dev/null +++ b/bsps/powerpc/beatnik/marvell/gt.c @@ -0,0 +1,1010 @@ +/* $NetBSD: gt.c,v 1.5 2003/07/14 15:47:16 lukem Exp $ */ + +/* + * Copyright (c) 2002 Allegro Networks, Inc., Wasabi Systems, Inc. + * All rights reserved. + * + * 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 for the NetBSD Project by + * Allegro Networks, Inc., and Wasabi Systems, Inc. + * 4. The name of Allegro Networks, Inc. may not be used to endorse + * or promote products derived from this software without specific prior + * written permission. + * 5. The name of Wasabi Systems, Inc. may not be used to endorse + * or promote products derived from this software without specific prior + * written permission. + * + * THIS SOFTWARE IS PROVIDED BY ALLEGRO NETWORKS, INC. AND + * WASABI SYSTEMS, INC. ``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 EITHER ALLEGRO NETWORKS, INC. OR WASABI SYSTEMS, INC. + * 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. + */ + +/* + * gt.c -- GT system controller driver + */ + +#include <sys/cdefs.h> +__KERNEL_RCSID(0, "$NetBSD: gt.c,v 1.5 2003/07/14 15:47:16 lukem Exp $"); + +#include "opt_marvell.h" + +#include <sys/param.h> +#include <sys/types.h> +#include <sys/cdefs.h> +#include <sys/extent.h> +#include <sys/device.h> +#include <sys/kernel.h> +#include <sys/malloc.h> + +#define _BUS_SPACE_PRIVATE +#define _BUS_DMA_PRIVATE +#include <machine/bus.h> + +#include <powerpc/spr.h> +#include <powerpc/oea/hid.h> + +#include <dev/marvell/gtreg.h> +#include <dev/marvell/gtintrreg.h> +#include <dev/marvell/gtvar.h> +#include <dev/marvell/gtethreg.h> + +#ifdef DEBUG +#include <sys/systm.h> /* for Debugger() */ +#endif + +#if ((GT_MPP_WATCHDOG & 0xf0f0f0f0) != 0) +# error /* unqualified: configuration botch! */ +#endif +#if ((GT_MPP_WATCHDOG & GT_MPP_INTERRUPTS) != 0) +# error /* conflict: configuration botch! */ +#endif + +static void gt_comm_intr_enb(struct gt_softc *); +static void gt_devbus_intr_enb(struct gt_softc *); +#ifdef GT_ECC +static void gt_ecc_intr_enb(struct gt_softc *); +#endif + +void gt_init_hostid (struct gt_softc *); +void gt_init_interrupt (struct gt_softc *); +static int gt_comm_intr (void *); + +void gt_watchdog_init(struct gt_softc *); +void gt_watchdog_enable(void); +void gt_watchdog_disable(void); +void gt_watchdog_reset(void); + +extern struct cfdriver gt_cd; + +static int gtfound = 0; + +static struct gt_softc *gt_watchdog_sc = 0; +static int gt_watchdog_state = 0; + +int +gt_cfprint (void *aux, const char *pnp) +{ + struct gt_attach_args *ga = aux; + + if (pnp) { + aprint_normal("%s at %s", ga->ga_name, pnp); + } + + aprint_normal(" unit %d", ga->ga_unit); + return (UNCONF); +} + + +static int +gt_cfsearch(struct device *parent, struct cfdata *cf, void *aux) +{ + struct gt_softc *gt = (struct gt_softc *) parent; + struct gt_attach_args ga; + + ga.ga_name = cf->cf_name; + ga.ga_dmat = gt->gt_dmat; + ga.ga_memt = gt->gt_memt; + ga.ga_memh = gt->gt_memh; + ga.ga_unit = cf->cf_loc[GTCF_UNIT]; + + if (config_match(parent, cf, &ga) > 0) + config_attach(parent, cf, &ga, gt_cfprint); + + return (0); +} + +void +gt_attach_common(struct gt_softc *gt) +{ + uint32_t cpucfg, cpumode, cpumstr; +#ifdef DEBUG + uint32_t loaddr, hiaddr; +#endif + + gtfound = 1; + + cpumode = gt_read(gt, GT_CPU_Mode); + aprint_normal(": id %d", GT_CPUMode_MultiGTID_GET(cpumode)); + if (cpumode & GT_CPUMode_MultiGT) + aprint_normal (" (multi)"); + switch (GT_CPUMode_CPUType_GET(cpumode)) { + case 4: aprint_normal(", 60x bus"); break; + case 5: aprint_normal(", MPX bus"); break; + default: aprint_normal(", %#x(?) bus", GT_CPUMode_CPUType_GET(cpumode)); break; + } + + cpumstr = gt_read(gt, GT_CPU_Master_Ctl); + cpumstr &= ~(GT_CPUMstrCtl_CleanBlock|GT_CPUMstrCtl_FlushBlock); +#if 0 + cpumstr |= GT_CPUMstrCtl_CleanBlock|GT_CPUMstrCtl_FlushBlock; +#endif + gt_write(gt, GT_CPU_Master_Ctl, cpumstr); + + switch (cpumstr & (GT_CPUMstrCtl_CleanBlock|GT_CPUMstrCtl_FlushBlock)) { + case 0: break; + case GT_CPUMstrCtl_CleanBlock: aprint_normal(", snoop=clean"); break; + case GT_CPUMstrCtl_FlushBlock: aprint_normal(", snoop=flush"); break; + case GT_CPUMstrCtl_CleanBlock|GT_CPUMstrCtl_FlushBlock: + aprint_normal(", snoop=clean&flush"); break; + } + aprint_normal(" wdog=%#x,%#x\n", + gt_read(gt, GT_WDOG_Config), + gt_read(gt, GT_WDOG_Value)); + +#if DEBUG + loaddr = GT_LowAddr_GET(gt_read(gt, GT_SCS0_Low_Decode)); + hiaddr = GT_HighAddr_GET(gt_read(gt, GT_SCS0_High_Decode)); + aprint_normal("%s: scs[0]=%#10x-%#10x\n", gt->gt_dev.dv_xname, loaddr, hiaddr); + + loaddr = GT_LowAddr_GET(gt_read(gt, GT_SCS1_Low_Decode)); + hiaddr = GT_HighAddr_GET(gt_read(gt, GT_SCS1_High_Decode)); + aprint_normal("%s: scs[1]=%#10x-%#10x\n", gt->gt_dev.dv_xname, loaddr, hiaddr); + + loaddr = GT_LowAddr_GET(gt_read(gt, GT_SCS2_Low_Decode)); + hiaddr = GT_HighAddr_GET(gt_read(gt, GT_SCS2_High_Decode)); + aprint_normal("%s: scs[2]=%#10x-%#10x\n", gt->gt_dev.dv_xname, loaddr, hiaddr); + + loaddr = GT_LowAddr_GET(gt_read(gt, GT_SCS3_Low_Decode)); + hiaddr = GT_HighAddr_GET(gt_read(gt, GT_SCS3_High_Decode)); + aprint_normal("%s: scs[3]=%#10x-%#10x\n", gt->gt_dev.dv_xname, loaddr, hiaddr); + + loaddr = GT_LowAddr_GET(gt_read(gt, GT_CS0_Low_Decode)); + hiaddr = GT_HighAddr_GET(gt_read(gt, GT_CS0_High_Decode)); + aprint_normal("%s: cs[0]=%#10x-%#10x\n", gt->gt_dev.dv_xname, loaddr, hiaddr); + + loaddr = GT_LowAddr_GET(gt_read(gt, GT_CS1_Low_Decode)); + hiaddr = GT_HighAddr_GET(gt_read(gt, GT_CS1_High_Decode)); + aprint_normal("%s: cs[1]=%#10x-%#10x\n", gt->gt_dev.dv_xname, loaddr, hiaddr); + + loaddr = GT_LowAddr_GET(gt_read(gt, GT_CS2_Low_Decode)); + hiaddr = GT_HighAddr_GET(gt_read(gt, GT_CS2_High_Decode)); + aprint_normal("%s: cs[2]=%#10x-%#10x\n", gt->gt_dev.dv_xname, loaddr, hiaddr); + + loaddr = GT_LowAddr_GET(gt_read(gt, GT_CS3_Low_Decode)); + hiaddr = GT_HighAddr_GET(gt_read(gt, GT_CS3_High_Decode)); + aprint_normal("%s: cs[3]=%#10x-%#10x\n", gt->gt_dev.dv_xname, loaddr, hiaddr); + + loaddr = GT_LowAddr_GET(gt_read(gt, GT_BootCS_Low_Decode)); + hiaddr = GT_HighAddr_GET(gt_read(gt, GT_BootCS_High_Decode)); + aprint_normal("%s: bootcs=%#10x-%#10x\n", gt->gt_dev.dv_xname, loaddr, hiaddr); + + loaddr = GT_LowAddr_GET(gt_read(gt, GT_PCI0_IO_Low_Decode)); + hiaddr = GT_HighAddr_GET(gt_read(gt, GT_PCI0_IO_High_Decode)); + aprint_normal("%s: pci0io=%#10x-%#10x ", gt->gt_dev.dv_xname, loaddr, hiaddr); + + loaddr = gt_read(gt, GT_PCI0_IO_Remap); + aprint_normal("remap=%#010x\n", loaddr); + + loaddr = GT_LowAddr_GET(gt_read(gt, GT_PCI0_Mem0_Low_Decode)); + hiaddr = GT_HighAddr_GET(gt_read(gt, GT_PCI0_Mem0_High_Decode)); + aprint_normal("%s: pci0mem[0]=%#10x-%#10x ", gt->gt_dev.dv_xname, loaddr, hiaddr); + + loaddr = gt_read(gt, GT_PCI0_Mem0_Remap_Low); + hiaddr = gt_read(gt, GT_PCI0_Mem0_Remap_High); + aprint_normal("remap=%#010x.%#010x\n", hiaddr, loaddr); + + loaddr = GT_LowAddr_GET(gt_read(gt, GT_PCI0_Mem1_Low_Decode)); + hiaddr = GT_HighAddr_GET(gt_read(gt, GT_PCI0_Mem1_High_Decode)); + aprint_normal("%s: pci0mem[1]=%#10x-%#10x ", gt->gt_dev.dv_xname, loaddr, hiaddr); + + loaddr = gt_read(gt, GT_PCI0_Mem1_Remap_Low); + hiaddr = gt_read(gt, GT_PCI0_Mem1_Remap_High); + aprint_normal("remap=%#010x.%#010x\n", hiaddr, loaddr); + + loaddr = GT_LowAddr_GET(gt_read(gt, GT_PCI0_Mem2_Low_Decode)); + hiaddr = GT_HighAddr_GET(gt_read(gt, GT_PCI0_Mem2_High_Decode)); + aprint_normal("%s: pci0mem[2]=%#10x-%#10x ", gt->gt_dev.dv_xname, loaddr, hiaddr); + + loaddr = gt_read(gt, GT_PCI0_Mem2_Remap_Low); + hiaddr = gt_read(gt, GT_PCI0_Mem2_Remap_High); + aprint_normal("remap=%#010x.%#010x\n", hiaddr, loaddr); + + loaddr = GT_LowAddr_GET(gt_read(gt, GT_PCI0_Mem3_Low_Decode)); + hiaddr = GT_HighAddr_GET(gt_read(gt, GT_PCI0_Mem3_High_Decode)); + aprint_normal("%s: pci0mem[3]=%#10x-%#10x ", gt->gt_dev.dv_xname, loaddr, hiaddr); + + loaddr = gt_read(gt, GT_PCI0_Mem3_Remap_Low); + hiaddr = gt_read(gt, GT_PCI0_Mem3_Remap_High); + aprint_normal("remap=%#010x.%#010x\n", hiaddr, loaddr); + + loaddr = GT_LowAddr_GET(gt_read(gt, GT_PCI1_IO_Low_Decode)); + hiaddr = GT_HighAddr_GET(gt_read(gt, GT_PCI1_IO_High_Decode)); + aprint_normal("%s: pci1io=%#10x-%#10x ", gt->gt_dev.dv_xname, loaddr, hiaddr); + + loaddr = gt_read(gt, GT_PCI1_IO_Remap); + aprint_normal("remap=%#010x\n", loaddr); + + loaddr = GT_LowAddr_GET(gt_read(gt, GT_PCI1_Mem0_Low_Decode)); + hiaddr = GT_HighAddr_GET(gt_read(gt, GT_PCI1_Mem0_High_Decode)); + aprint_normal("%s: pci1mem[0]=%#10x-%#10x ", gt->gt_dev.dv_xname, loaddr, hiaddr); + + loaddr = gt_read(gt, GT_PCI1_Mem0_Remap_Low); + hiaddr = gt_read(gt, GT_PCI1_Mem0_Remap_High); + aprint_normal("remap=%#010x.%#010x\n", hiaddr, loaddr); + + loaddr = GT_LowAddr_GET(gt_read(gt, GT_PCI1_Mem1_Low_Decode)); + hiaddr = GT_HighAddr_GET(gt_read(gt, GT_PCI1_Mem1_High_Decode)); + aprint_normal("%s: pci1mem[1]=%#10x-%#10x ", gt->gt_dev.dv_xname, loaddr, hiaddr); + + loaddr = gt_read(gt, GT_PCI1_Mem1_Remap_Low); + hiaddr = gt_read(gt, GT_PCI1_Mem1_Remap_High); + aprint_normal("remap=%#010x.%#010x\n", hiaddr, loaddr); + + loaddr = GT_LowAddr_GET(gt_read(gt, GT_PCI1_Mem2_Low_Decode)); + hiaddr = GT_HighAddr_GET(gt_read(gt, GT_PCI1_Mem2_High_Decode)); + aprint_normal("%s: pci1mem[2]=%#10x-%#10x ", gt->gt_dev.dv_xname, loaddr, hiaddr); + + loaddr = gt_read(gt, GT_PCI1_Mem2_Remap_Low); + hiaddr = gt_read(gt, GT_PCI1_Mem2_Remap_High); + aprint_normal("remap=%#010x.%#010x\n", hiaddr, loaddr); + + loaddr = GT_LowAddr_GET(gt_read(gt, GT_PCI1_Mem3_Low_Decode)); + hiaddr = GT_HighAddr_GET(gt_read(gt, GT_PCI1_Mem3_High_Decode)); + aprint_normal("%s: pci1mem[3]=%#10x-%#10x ", gt->gt_dev.dv_xname, loaddr, hiaddr); + + loaddr = gt_read(gt, GT_PCI1_Mem3_Remap_Low); + hiaddr = gt_read(gt, GT_PCI1_Mem3_Remap_High); + aprint_normal("remap=%#010x.%#010x\n", hiaddr, loaddr); + + loaddr = GT_LowAddr_GET(gt_read(gt, GT_Internal_Decode)); + aprint_normal("%s: internal=%#10x-%#10x\n", gt->gt_dev.dv_xname, + loaddr, loaddr+256*1024); + + loaddr = GT_LowAddr_GET(gt_read(gt, GT_CPU0_Low_Decode)); + hiaddr = GT_HighAddr_GET(gt_read(gt, GT_CPU0_High_Decode)); + aprint_normal("%s: cpu0=%#10x-%#10x\n", gt->gt_dev.dv_xname, loaddr, hiaddr); + + loaddr = GT_LowAddr_GET(gt_read(gt, GT_CPU1_Low_Decode)); + hiaddr = GT_HighAddr_GET(gt_read(gt, GT_CPU1_High_Decode)); + aprint_normal("%s: cpu1=%#10x-%#10x", gt->gt_dev.dv_xname, loaddr, hiaddr); +#endif + + aprint_normal("%s:", gt->gt_dev.dv_xname); + + cpucfg = gt_read(gt, GT_CPU_Cfg); + cpucfg |= GT_CPUCfg_ConfSBDis; /* per errata #46 */ + cpucfg |= GT_CPUCfg_AACKDelay; /* per restriction #18 */ + gt_write(gt, GT_CPU_Cfg, cpucfg); + if (cpucfg & GT_CPUCfg_Pipeline) + aprint_normal(" pipeline"); + if (cpucfg & GT_CPUCfg_AACKDelay) + aprint_normal(" aack-delay"); + if (cpucfg & GT_CPUCfg_RdOOO) + aprint_normal(" read-ooo"); + if (cpucfg & GT_CPUCfg_IOSBDis) + aprint_normal(" io-sb-dis"); + if (cpucfg & GT_CPUCfg_ConfSBDis) + aprint_normal(" conf-sb-dis"); + if (cpucfg & GT_CPUCfg_ClkSync) + aprint_normal(" clk-sync"); + aprint_normal("\n"); + + gt_init_hostid(gt); + + gt_watchdog_init(gt); + + gt_init_interrupt(gt); + +#ifdef GT_ECC + gt_ecc_intr_enb(gt); +#endif + + gt_comm_intr_enb(gt); + gt_devbus_intr_enb(gt); + + gt_watchdog_disable(); + config_search(gt_cfsearch, >->gt_dev, NULL); + gt_watchdog_service(); + gt_watchdog_enable(); +} + +void +gt_init_hostid(struct gt_softc *gt) +{ + + hostid = 1; /* XXX: Used by i2c; needs work -- AKB */ +} + +void +gt_init_interrupt(struct gt_softc *gt) +{ + u_int32_t mppirpts = GT_MPP_INTERRUPTS; /* from config */ + u_int32_t r; + u_int32_t mppbit; + u_int32_t mask; + u_int32_t mppsel; + u_int32_t regoff; + + gt_write(gt, ICR_CIM_LO, 0); + gt_write(gt, ICR_CIM_HI, 0); + + /* + * configure the GPP interrupts: + * - set the configured MPP pins in GPP mode + * - set the configured GPP pins to input, active low, interrupt enbl + */ +#ifdef DEBUG + printf("%s: mpp cfg ", gt->gt_dev.dv_xname); + for (regoff = GT_MPP_Control0; regoff <= GT_MPP_Control3; regoff += 4) + printf("%#x ", gt_read(gt, regoff)); + printf(", mppirpts 0x%x\n", mppirpts); +#endif + mppbit = 0x1; + for (regoff = GT_MPP_Control0; regoff <= GT_MPP_Control3; regoff += 4) { + mask = 0; + for (mppsel = 0xf; mppsel; mppsel <<= 4) { + if (mppirpts & mppbit) + mask |= mppsel; + mppbit <<= 1; + } + if (mask) { + r = gt_read(gt, regoff); + r &= ~mask; + gt_write(gt, regoff, r); + } + } + + r = gt_read(gt, GT_GPP_IO_Control); + r &= ~mppirpts; + gt_write(gt, GT_GPP_IO_Control, r); + + r = gt_read(gt, GT_GPP_Level_Control); + r |= mppirpts; + gt_write(gt, GT_GPP_Level_Control, r); + + r = gt_read(gt, GT_GPP_Interrupt_Mask); + r |= mppirpts; + gt_write(gt, GT_GPP_Interrupt_Mask, r); +} + +uint32_t +gt_read_mpp (void) +{ + return gt_read((struct gt_softc *)gt_cd.cd_devs[0], GT_GPP_Value); +} + +#if 0 +int +gt_bs_extent_init(struct discovery_bus_space *bs, char *name) +{ + u_long start, end; + int i, j, error; + + if (bs->bs_nregion == 0) { + bs->bs_extent = extent_create(name, 0xffffffffUL, 0xffffffffUL, + M_DEVBUF, NULL, 0, EX_NOCOALESCE|EX_WAITOK); + KASSERT(bs->bs_extent != NULL); + return 0; + } + /* + * Find the top and bottoms of this bus space. + */ + start = bs->bs_regions[0].br_start; + end = bs->bs_regions[0].br_end; +#ifdef DEBUG + if (gtpci_debug > 1) + printf("gtpci_bs_extent_init: %s: region %d: %#lx-%#lx\n", + name, 0, bs->bs_regions[0].br_start, + bs->bs_regions[0].br_end); +#endif + for (i = 1; i < bs->bs_nregion; i++) { + if (bs->bs_regions[i].br_start < start) + start = bs->bs_regions[i].br_start; + if (bs->bs_regions[i].br_end > end) + end = bs->bs_regions[i].br_end; +#ifdef DEBUG + if (gtpci_debug > 1) + printf("gtpci_bs_extent_init: %s: region %d:" + " %#lx-%#lx\n", + name, i, bs->bs_regions[i].br_start, + bs->bs_regions[i].br_end); +#endif + } + /* + * Now that we have the top and bottom limits of this + * bus space, create the extent map that will manage this + * space for us. + */ +#ifdef DEBUG + if (gtpci_debug > 1) + printf("gtpci_bs_extent_init: %s: create: %#lx-%#lx\n", + name, start, end); +#endif + bs->bs_extent = extent_create(name, start, end, M_DEVBUF, + NULL, 0, EX_NOCOALESCE|EX_WAITOK); + KASSERT(bs->bs_extent != NULL); + + /* If there was more than one bus space region, then there + * might gaps in between them. Allocate the gap so that + * they will not be legal addresses in the extent. + */ + for (i = 0; i < bs->bs_nregion && bs->bs_nregion > 1; i++) { + /* Initial start is "infinity" and the inital end is + * is the end of this bus region. + */ + start = ~0UL; + end = bs->bs_regions[i].br_end; + /* For each region, if it starts after this region but less + * than the saved start, use its start address. If the start + * address is one past the end address, then we're done + */ + for (j = 0; j < bs->bs_nregion && start > end + 1; j++) { + if (i == j) + continue; + if (bs->bs_regions[j].br_start > end && + bs->bs_regions[j].br_start < start) + start = bs->bs_regions[j].br_start; + } + /* + * If we found a gap, allocate it away. + */ + if (start != ~0UL && start != end + 1) { +#ifdef DEBUG + if (gtpci_debug > 1) + printf("gtpci_bs_extent_init: %s: alloc(hole): %#lx-%#lx\n", + name, end + 1, start - 1); +#endif + error = extent_alloc_region(bs->bs_extent, end + 1, + start - (end + 1), EX_NOWAIT); + KASSERT(error == 0); + } + } + return 1; +} +#endif + +/* + * unknown board, enable everything + */ +# define GT_CommUnitIntr_DFLT GT_CommUnitIntr_S0|GT_CommUnitIntr_S1 \ + |GT_CommUnitIntr_E0|GT_CommUnitIntr_E1 \ + |GT_CommUnitIntr_E2 + +static const char * const gt_comm_subunit_name[8] = { + "ethernet 0", + "ethernet 1", + "ethernet 2", + "(reserved)", + "MPSC 0", + "MPSC 1", + "(reserved)", + "(sel)", +}; + +static int +gt_comm_intr(void *arg) +{ + struct gt_softc *gt = (struct gt_softc *)arg; + u_int32_t cause; + u_int32_t addr; + unsigned int mask; + int i; + + cause = gt_read(gt, GT_CommUnitIntr_Cause); + gt_write(gt, GT_CommUnitIntr_Cause, ~cause); + addr = gt_read(gt, GT_CommUnitIntr_ErrAddr); + + printf("%s: Comm Unit irpt, cause %#x addr %#x\n", + gt->gt_dev.dv_xname, cause, addr); + + cause &= GT_CommUnitIntr_DFLT; + if (cause == 0) + return 0; + + mask = 0x7; + for (i=0; i<7; i++) { + if (cause & mask) { + printf("%s: Comm Unit %s:", gt->gt_dev.dv_xname, + gt_comm_subunit_name[i]); + if (cause & 1) + printf(" AddrMiss"); + if (cause & 2) + printf(" AccProt"); + if (cause & 4) + printf(" WrProt"); + printf("\n"); + } + cause >>= 4; + } + return 1; +} + +/* + * gt_comm_intr_init - enable GT-64260 Comm Unit interrupts + */ +static void +gt_comm_intr_enb(struct gt_softc *gt) +{ + u_int32_t cause; + + cause = gt_read(gt, GT_CommUnitIntr_Cause); + if (cause) + gt_write(gt, GT_CommUnitIntr_Cause, ~cause); + gt_write(gt, GT_CommUnitIntr_Mask, GT_CommUnitIntr_DFLT); + (void)gt_read(gt, GT_CommUnitIntr_ErrAddr); + + intr_establish(IRQ_COMM, IST_LEVEL, IPL_GTERR, gt_comm_intr, gt); + printf("%s: Comm Unit irpt at %d\n", gt->gt_dev.dv_xname, IRQ_COMM); +} + +#ifdef GT_ECC +static char *gt_ecc_intr_str[4] = { + "(none)", + "single bit", + "double bit", + "(reserved)" +}; + +static int +gt_ecc_intr(void *arg) +{ + struct gt_softc *gt = (struct gt_softc *)arg; + u_int32_t addr; + u_int32_t dlo; + u_int32_t dhi; + u_int32_t rec; + u_int32_t calc; + u_int32_t count; + int err; + + count = gt_read(gt, GT_ECC_Count); + dlo = gt_read(gt, GT_ECC_Data_Lo); + dhi = gt_read(gt, GT_ECC_Data_Hi); + rec = gt_read(gt, GT_ECC_Rec); + calc = gt_read(gt, GT_ECC_Calc); + addr = gt_read(gt, GT_ECC_Addr); /* read last! */ + gt_write(gt, GT_ECC_Addr, 0); /* clear irpt */ + + err = addr & 0x3; + + printf("%s: ECC error: %s: " + "addr %#x data %#x.%#x rec %#x calc %#x cnt %#x\n", + gt->gt_dev.dv_xname, gt_ecc_intr_str[err], + addr, dhi, dlo, rec, calc, count); + + if (err == 2) + panic("ecc"); + + return (err == 1); +} + +/* + * gt_ecc_intr_enb - enable GT-64260 ECC interrupts + */ +static void +gt_ecc_intr_enb(struct gt_softc *gt) +{ + u_int32_t ctl; + + ctl = gt_read(gt, GT_ECC_Ctl); + ctl |= 1 << 16; /* XXX 1-bit threshold == 1 */ + gt_write(gt, GT_ECC_Ctl, ctl); + (void)gt_read(gt, GT_ECC_Data_Lo); + (void)gt_read(gt, GT_ECC_Data_Hi); + (void)gt_read(gt, GT_ECC_Rec); + (void)gt_read(gt, GT_ECC_Calc); + (void)gt_read(gt, GT_ECC_Addr); /* read last! */ + gt_write(gt, GT_ECC_Addr, 0); /* clear irpt */ + + intr_establish(IRQ_ECC, IST_LEVEL, IPL_GTERR, gt_ecc_intr, gt); + printf("%s: ECC irpt at %d\n", gt->gt_dev.dv_xname, IRQ_ECC); +} +#endif /* GT_ECC */ + + +#ifndef GT_MPP_WATCHDOG +void +gt_watchdog_init(struct gt_softc *gt) +{ + u_int32_t r; + unsigned int omsr; + + omsr = extintr_disable(); + + printf("%s: watchdog", gt->gt_dev.dv_xname); + + /* + * handle case where firmware started watchdog + */ + r = gt_read(gt, GT_WDOG_Config); + printf(" status %#x,%#x:", + r, gt_read(gt, GT_WDOG_Value)); + if ((r & 0x80000000) != 0) { + gt_watchdog_sc = gt; /* enabled */ + gt_watchdog_state = 1; + printf(" firmware-enabled\n"); + gt_watchdog_service(); + return; + } else { + printf(" firmware-disabled\n"); + } + + extintr_restore(omsr); +} + +#else /* GT_MPP_WATCHDOG */ + +void +gt_watchdog_init(struct gt_softc *gt) +{ + u_int32_t mpp_watchdog = GT_MPP_WATCHDOG; /* from config */ + u_int32_t r; + u_int32_t cfgbits; + u_int32_t mppbits; + u_int32_t mppmask=0; + u_int32_t regoff; + unsigned int omsr; + + printf("%s: watchdog", gt->gt_dev.dv_xname); + + if (mpp_watchdog == 0) { + printf(" not configured\n"); + return; + } + +#if 0 + if (afw_wdog_ctl == 1) { + printf(" admin disabled\n"); + return; + } +#endif + + omsr = extintr_disable(); + + /* + * if firmware started watchdog, we disable and start + * from scratch to get it in a known state. + * + * on GT-64260A we always see 0xffffffff + * in both the GT_WDOG_Config_Enb and GT_WDOG_Value regsiters. + * Use AFW-supplied flag to determine run state. + */ + r = gt_read(gt, GT_WDOG_Config); + if (r != ~0) { + if ((r & GT_WDOG_Config_Enb) != 0) { + gt_write(gt, GT_WDOG_Config, + (GT_WDOG_Config_Ctl1a | GT_WDOG_Preset_DFLT)); + gt_write(gt, GT_WDOG_Config, + (GT_WDOG_Config_Ctl1b | GT_WDOG_Preset_DFLT)); + } + } else { +#if 0 + if (afw_wdog_state == 1) { + gt_write(gt, GT_WDOG_Config, + (GT_WDOG_Config_Ctl1a | GT_WDOG_Preset_DFLT)); + gt_write(gt, GT_WDOG_Config, + (GT_WDOG_Config_Ctl1b | GT_WDOG_Preset_DFLT)); + } +#endif + } + + /* + * "the watchdog timer can be activated only after + * configuring two MPP pins to act as WDE and WDNMI" + */ + mppbits = 0; + cfgbits = 0x3; + for (regoff = GT_MPP_Control0; regoff <= GT_MPP_Control3; regoff += 4) { + if ((mpp_watchdog & cfgbits) == cfgbits) { + mppbits = 0x99; + mppmask = 0xff; + break; + } + cfgbits <<= 2; + if ((mpp_watchdog & cfgbits) == cfgbits) { + mppbits = 0x9900; + mppmask = 0xff00; + break; + } + cfgbits <<= 6; /* skip unqualified bits */ + } + if (mppbits == 0) { + printf(" config error\n"); + extintr_restore(omsr); + return; + } + + r = gt_read(gt, regoff); + r &= ~mppmask; + r |= mppbits; + gt_write(gt, regoff, r); + printf(" mpp %#x %#x", regoff, mppbits); + + gt_write(gt, GT_WDOG_Value, GT_WDOG_NMI_DFLT); + + gt_write(gt, GT_WDOG_Config, + (GT_WDOG_Config_Ctl1a | GT_WDOG_Preset_DFLT)); + gt_write(gt, GT_WDOG_Config, + (GT_WDOG_Config_Ctl1b | GT_WDOG_Preset_DFLT)); + + + r = gt_read(gt, GT_WDOG_Config), + printf(" status %#x,%#x: %s", + r, gt_read(gt, GT_WDOG_Value), + ((r & GT_WDOG_Config_Enb) != 0) ? "enabled" : "botch"); + + if ((r & GT_WDOG_Config_Enb) != 0) { + register_t hid0; + + gt_watchdog_sc = gt; /* enabled */ + gt_watchdog_state = 1; + + /* + * configure EMCP in HID0 in case it's not already set + */ + __asm __volatile("sync":::"memory"); + hid0 = mfspr(SPR_HID0); + if ((hid0 & HID0_EMCP) == 0) { + hid0 |= HID0_EMCP; + __asm __volatile("sync":::"memory"); mtspr(SPR_HID0, hid0); + __asm __volatile("sync":::"memory"); hid0 = mfspr(SPR_HID0); + printf(", EMCP set"); + } + } + printf("\n"); + + extintr_restore(omsr); +} +#endif /* GT_MPP_WATCHDOG */ + +#ifdef DEBUG +u_int32_t hid0_print(void); +u_int32_t +hid0_print() +{ + u_int32_t hid0; + __asm __volatile("sync; mfspr %0,1008;" : "=r"(hid0)::"memory"); + printf("hid0: %#x\n", hid0); + return hid0; +} +#endif + +void +gt_watchdog_enable(void) +{ + struct gt_softc *gt; + unsigned int omsr; + + omsr = extintr_disable(); + gt = gt_watchdog_sc; + if ((gt != NULL) && (gt_watchdog_state == 0)) { + gt_watchdog_state = 1; + + gt_write(gt, GT_WDOG_Config, + (GT_WDOG_Config_Ctl1a | GT_WDOG_Preset_DFLT)); + gt_write(gt, GT_WDOG_Config, + (GT_WDOG_Config_Ctl1b | GT_WDOG_Preset_DFLT)); + } + extintr_restore(omsr); +} + +void +gt_watchdog_disable(void) +{ + struct gt_softc *gt; + unsigned int omsr; + + omsr = extintr_disable(); + gt = gt_watchdog_sc; + if ((gt != NULL) && (gt_watchdog_state != 0)) { + gt_watchdog_state = 0; + + gt_write(gt, GT_WDOG_Config, + (GT_WDOG_Config_Ctl1a | GT_WDOG_Preset_DFLT)); + gt_write(gt, GT_WDOG_Config, + (GT_WDOG_Config_Ctl1b | GT_WDOG_Preset_DFLT)); + } + extintr_restore(omsr); +} + +#ifdef DEBUG +int inhibit_watchdog_service = 0; +#endif +void +gt_watchdog_service(void) +{ + struct gt_softc *gt = gt_watchdog_sc; + + if ((gt == NULL) || (gt_watchdog_state == 0)) + return; /* not enabled */ +#ifdef DEBUG + if (inhibit_watchdog_service) + return; +#endif + + gt_write(gt, GT_WDOG_Config, + (GT_WDOG_Config_Ctl2a | GT_WDOG_Preset_DFLT)); + gt_write(gt, GT_WDOG_Config, + (GT_WDOG_Config_Ctl2b | GT_WDOG_Preset_DFLT)); +} + +/* + * gt_watchdog_reset - force a watchdog reset using Preset_VAL=0 + */ +void +gt_watchdog_reset() +{ + struct gt_softc *gt = gt_watchdog_sc; + u_int32_t r; + + (void)extintr_disable(); + r = gt_read(gt, GT_WDOG_Config); + gt_write(gt, GT_WDOG_Config, (GT_WDOG_Config_Ctl1a | 0)); + gt_write(gt, GT_WDOG_Config, (GT_WDOG_Config_Ctl1b | 0)); + if ((r & GT_WDOG_Config_Enb) != 0) { + /* + * was enabled, we just toggled it off, toggle on again + */ + gt_write(gt, GT_WDOG_Config, + (GT_WDOG_Config_Ctl1a | 0)); + gt_write(gt, GT_WDOG_Config, + (GT_WDOG_Config_Ctl1b | 0)); + } + for(;;); +} + +static int +gt_devbus_intr(void *arg) +{ + struct gt_softc *gt = (struct gt_softc *)arg; + u_int32_t cause; + u_int32_t addr; + + cause = gt_read(gt, GT_DEVBUS_ICAUSE); + addr = gt_read(gt, GT_DEVBUS_ERR_ADDR); + gt_write(gt, GT_DEVBUS_ICAUSE, 0); /* clear irpt */ + + if (cause & GT_DEVBUS_DBurstErr) { + printf("%s: Device Bus error: burst violation", + gt->gt_dev.dv_xname); + if ((cause & GT_DEVBUS_Sel) == 0) + printf(", addr %#x", addr); + printf("\n"); + } + if (cause & GT_DEVBUS_DRdyErr) { + printf("%s: Device Bus error: ready timer expired", + gt->gt_dev.dv_xname); + if ((cause & GT_DEVBUS_Sel) != 0) + printf(", addr %#x\n", addr); + printf("\n"); + } + + return (cause != 0); +} + +/* + * gt_ecc_intr_enb - enable GT-64260 ECC interrupts + */ +static void +gt_devbus_intr_enb(struct gt_softc *gt) +{ + gt_write(gt, GT_DEVBUS_IMASK, + GT_DEVBUS_DBurstErr|GT_DEVBUS_DRdyErr); + (void)gt_read(gt, GT_DEVBUS_ERR_ADDR); /* clear addr */ + gt_write(gt, GT_ECC_Addr, 0); /* clear irpt */ + + intr_establish(IRQ_DEV, IST_LEVEL, IPL_GTERR, gt_devbus_intr, gt); + printf("%s: Device Bus Error irpt at %d\n", + gt->gt_dev.dv_xname, IRQ_DEV); +} + + +int +gt_mii_read( + struct device *child, + struct device *parent, + int phy, + int reg) +{ + struct gt_softc * const gt = (struct gt_softc *) parent; + uint32_t data; + int count = 10000; + + do { + DELAY(10); + data = gt_read(gt, ETH_ESMIR); + } while ((data & ETH_ESMIR_Busy) && count-- > 0); + + if (count == 0) { + printf("%s: mii read for phy %d reg %d busied out\n", + child->dv_xname, phy, reg); + return ETH_ESMIR_Value_GET(data); + } + + gt_write(gt, ETH_ESMIR, ETH_ESMIR_READ(phy, reg)); + + count = 10000; + do { + DELAY(10); + data = gt_read(gt, ETH_ESMIR); + } while ((data & ETH_ESMIR_ReadValid) == 0 && count-- > 0); + + if (count == 0) + printf("%s: mii read for phy %d reg %d timed out\n", + child->dv_xname, phy, reg); +#if defined(GTMIIDEBUG) + printf("%s: mii_read(%d, %d): %#x data %#x\n", + child->dv_xname, phy, reg, + data, ETH_ESMIR_Value_GET(data)); +#endif + return ETH_ESMIR_Value_GET(data); +} + +void +gt_mii_write ( + struct device *child, + struct device *parent, + int phy, int reg, + int value) +{ + struct gt_softc * const gt = (struct gt_softc *) parent; + uint32_t data; + int count = 10000; + + do { + DELAY(10); + data = gt_read(gt, ETH_ESMIR); + } while ((data & ETH_ESMIR_Busy) && count-- > 0); + + if (count == 0) { + printf("%s: mii write for phy %d reg %d busied out (busy)\n", + child->dv_xname, phy, reg); + return; + } + + gt_write(gt, ETH_ESMIR, + ETH_ESMIR_WRITE(phy, reg, value)); + + count = 10000; + do { + DELAY(10); + data = gt_read(gt, ETH_ESMIR); + } while ((data & ETH_ESMIR_Busy) && count-- > 0); + + if (count == 0) + printf("%s: mii write for phy %d reg %d timed out\n", + child->dv_xname, phy, reg); +#if defined(GTMIIDEBUG) + printf("%s: mii_write(%d, %d, %#x)\n", + child->dv_xname, phy, reg, value); +#endif +} + diff --git a/bsps/powerpc/beatnik/marvell/gt_timer.c b/bsps/powerpc/beatnik/marvell/gt_timer.c new file mode 100644 index 0000000000..fd6960ea54 --- /dev/null +++ b/bsps/powerpc/beatnik/marvell/gt_timer.c @@ -0,0 +1,410 @@ +/* Driver for discovery timers and watchdog */ + +/* + * Acknowledgements: + * Valuable information was obtained from the following drivers + * netbsd: (C) Allegro Networks Inc; Wasabi Systems Inc. + * linux: (C) MontaVista, Software, Inc; Mark A. Greer. + * rtems: (C) Brookhaven National Laboratory; K. Feng + * but this implementation is original work by the author. + */ + +/* + * Authorship + * ---------- + * This software ('beatnik' RTEMS BSP for MVME6100 and MVME5500) was + * created by Till Straumann <strauman@slac.stanford.edu>, 2005-2007, + * Stanford Linear Accelerator Center, Stanford University. + * + * Acknowledgement of sponsorship + * ------------------------------ + * The 'beatnik' BSP was produced by + * the Stanford Linear Accelerator Center, Stanford University, + * under Contract DE-AC03-76SFO0515 with the Department of Energy. + * + * Government disclaimer of liability + * ---------------------------------- + * Neither the United States nor the United States Department of Energy, + * nor any of their employees, makes any warranty, express or implied, or + * assumes any legal liability or responsibility for the accuracy, + * completeness, or usefulness of any data, apparatus, product, or process + * disclosed, or represents that its use would not infringe privately owned + * rights. + * + * Stanford disclaimer of liability + * -------------------------------- + * Stanford University makes no representations or warranties, express or + * implied, nor assumes any liability for the use of this software. + * + * Stanford disclaimer of copyright + * -------------------------------- + * Stanford University, owner of the copyright, hereby disclaims its + * copyright and all other rights in this software. Hence, anyone may + * freely use it for any purpose without restriction. + * + * Maintenance of notices + * ---------------------- + * In the interest of clarity regarding the origin and status of this + * SLAC software, this and all the preceding Stanford University notices + * are to remain affixed to any copy or derivative of this software made + * or distributed by the recipient and are to be affixed to any copy of + * software made or distributed by the recipient that contains a copy or + * derivative of this software. + * + * ------------------ SLAC Software Notices, Set 4 OTT.002a, 2004 FEB 03 + */ + +#include <rtems.h> +#include <bsp/gtreg.h> +#include <libcpu/io.h> +#include <bsp.h> +#include <bsp/irq.h> +#include <rtems/bspIo.h> + +#include <stdint.h> + +#include <bsp/gt_timer.h> + +#define DEBUG + +static inline uint32_t gt_rd(uint32_t off) +{ + return in_le32( (volatile uint32_t *)(BSP_MV64x60_BASE+off) ); +} + +static inline void gt_wr(uint32_t off, uint32_t val) +{ + out_le32( (volatile uint32_t *)(BSP_MV64x60_BASE+off), val); +} + +static inline uint32_t gt_timer_bitmod(uint32_t off, uint32_t clr, uint32_t set) +{ + unsigned flags; + uint32_t rval; + + rtems_interrupt_disable(flags); + rval = gt_rd( off ); + gt_wr( off, (rval & ~clr) | set ); + rtems_interrupt_enable(flags); + return rval; +} + +#define GT_TIMER_MAX 3 +#define TIMER_ARGCHECK(t) do { if ((t)>GT_TIMER_MAX) return -1; } while (0) + +static struct { + void (*isr)(void *); + void *arg; +} gt_timer_isrs[GT_TIMER_MAX+1] = {{0},}; + +uint32_t BSP_timer_read(uint32_t timer) +{ + TIMER_ARGCHECK(timer); + return gt_rd(GT_TIMER_0 + (timer<<2)); +} + +int +BSP_timer_start(uint32_t timer, uint32_t period) +{ + TIMER_ARGCHECK(timer); + gt_wr(GT_TIMER_0 + (timer<<2), period); + return 0; +} + +int +BSP_timer_stop(uint32_t timer) +{ + TIMER_ARGCHECK(timer); + /* disable, clear period, re-enable */ + gt_timer_bitmod(GT_TIMER_0_3_Ctl, GT_TIMER_0_Ctl_Enb << (timer<<3), 0); + gt_wr(GT_TIMER_0 + (timer<<2), 0); + gt_timer_bitmod(GT_TIMER_0_3_Ctl, 0, GT_TIMER_0_Ctl_Enb << (timer<<3)); + return 0; +} + +int +BSP_timer_setup(uint32_t timer, void (*isr)(void *arg), void *arg, int reload) +{ + TIMER_ARGCHECK(timer); + if ( isr && gt_timer_isrs[timer].isr ) + return -1; + + BSP_timer_stop(timer); + /* mask and clear */ + gt_timer_bitmod(GT_TIMER_0_3_Intr_Msk, GT_TIMER_0_Intr<<timer, 0); + gt_timer_bitmod(GT_TIMER_0_3_Intr_Cse, GT_TIMER_0_Intr<<timer, 0); + + /* set reload bit */ + if ( reload ) + gt_timer_bitmod(GT_TIMER_0_3_Ctl, 0, GT_TIMER_0_Ctl_Rld << (timer<<3)); + else + gt_timer_bitmod(GT_TIMER_0_3_Ctl, GT_TIMER_0_Ctl_Rld << (timer<<3), 0); + + asm volatile("":::"memory"); + + if ( isr ) { + gt_timer_isrs[timer].isr = isr; + gt_timer_isrs[timer].arg = arg; + asm volatile("":::"memory"); + gt_timer_bitmod(GT_TIMER_0_3_Intr_Msk, 0, GT_TIMER_0_Intr<<timer); + } else { + gt_timer_isrs[timer].isr = 0; + gt_timer_isrs[timer].arg = 0; + } + return 0; +} + +static void +gt_timer_hdl(rtems_irq_hdl_param arg) +{ + int iarg = (int)arg; + int timer; + uint32_t bit; + + for ( ; iarg; iarg >>= 4 ) { + timer = (iarg & 0xf)-1; + bit = GT_TIMER_0_Intr<<timer; + if ( gt_timer_bitmod(GT_TIMER_0_3_Intr_Cse, bit, 0) & bit ) { + /* cause was set */ + if ( ! gt_timer_isrs[timer].isr ) { + printk("gt_timer: warning; no ISR connected but and IRQ happened (timer # %i)\n", timer); + /* mask */ + gt_timer_bitmod(GT_TIMER_0_3_Intr_Msk, bit, 0); + } else { + gt_timer_isrs[timer].isr(gt_timer_isrs[timer].arg); + } + } + } +} + +int +BSP_timers_initialize(void) +{ + rtems_irq_connect_data xx = {0}; + int i, ainc, arg; + + xx.hdl = gt_timer_hdl; + xx.on = 0; + xx.off = 0; + xx.isOn = 0; + + switch (BSP_getDiscoveryVersion(0)) { + case MV_64360: + i = 3; + ainc = 1; + arg = 4; + break; + default: + i = 1; + ainc = 0x0202; + arg = 0x0403; + break; + } + + for ( ; i>=0; i--, arg-=ainc ) { + xx.name = BSP_IRQ_TIME0_1 + i; + xx.handle = (rtems_irq_hdl_param)arg; + if ( !BSP_install_rtems_irq_handler(&xx) ) + return -1; + } + + return 0; +} + +#ifdef DEBUG_MODULAR +static int +BSP_timers_uninstall(void) +{ + rtems_irq_connect_data xx = {0}; + int i; + + xx.hdl = gt_timer_hdl; + xx.on = 0; + xx.off = 0; + xx.isOn = 0; + + for ( i=0; i<= GT_TIMER_MAX; i++ ) { + if ( BSP_timer_setup(i, 0, 0, 0) ) + return -1; + } + + switch (BSP_getDiscoveryVersion(0)) { + case MV_64360: + i = 3; + break; + default: + i = 1; + break; + } + + for ( ; i >= 0; i-- ) { + xx.name = BSP_IRQ_TIME0_1 + i; + BSP_get_current_rtems_irq_handler(&xx); + if ( !BSP_remove_rtems_irq_handler(&xx) ) + return -1; + } + + return 0; +} +#endif + +uint32_t +BSP_timer_clock_get(uint32_t timer) +{ + return BSP_bus_frequency; +} + +int BSP_timer_instances(void) +{ + return GT_TIMER_MAX + 1; +} + +/* On a 64260A we can't read the status (on/off), apparently + * so we maintain it locally and assume the firmware has + * not enabled the dog initially... + */ +static uint32_t wdog_on = 0x00ffffff; + +static uint32_t rd_wdcnf(void) +{ + uint32_t cnf = gt_rd(GT_WDOG_Config); + + /* BSD driver says that on the 64260A we always + * read 0xffffffff so we have to maintain the + * status locally (and hope we get the initial + * value right). + */ + if ( ~0 == cnf ) + cnf = wdog_on; + return cnf; +} + +/* change on/off state assume caller has IRQs disabled */ +static void dog_toggle(uint32_t ctl) +{ + ctl &= ~( GT_WDOG_Config_Ctl1a | GT_WDOG_Config_Ctl1b \ + | GT_WDOG_Config_Ctl2a | GT_WDOG_Config_Ctl2b); + gt_wr(GT_WDOG_Config, ctl | GT_WDOG_Config_Ctl1a); + gt_wr(GT_WDOG_Config, ctl | GT_WDOG_Config_Ctl1b); +} + +static void dog_pet(uint32_t ctl) +{ + ctl &= ~( GT_WDOG_Config_Ctl1a | GT_WDOG_Config_Ctl1b \ + | GT_WDOG_Config_Ctl2a | GT_WDOG_Config_Ctl2b); + gt_wr(GT_WDOG_Config, ctl | GT_WDOG_Config_Ctl2a); + gt_wr(GT_WDOG_Config, ctl | GT_WDOG_Config_Ctl2b); +} + + +/* Enable watchdog and set a timeout (in us) + * a timeout of 0xffffffff selects the old/existing + * timeout. + * + * RETURNS 0 on success + */ +int +BSP_watchdog_enable(uint32_t timeout_us) +{ + unsigned long long x = timeout_us; + unsigned flags; + uint32_t ctl; + + x *= BSP_bus_frequency; + x /= 256; /* there seems to be a prescaler */ + x /= 1000000; /* us/s */ + + if ( x > (1<<24)-1 ) + x = (1<<24)-1; + + if ( 0xffffffff != timeout_us ) + timeout_us = x; + + rtems_interrupt_disable(flags); + + ctl = rd_wdcnf(); + + /* if enabled, disable first */ + if ( GT_WDOG_Config_Enb & ctl ) { + dog_toggle(ctl); + } + if ( 0xffffffff == timeout_us ) { + timeout_us = ctl & ((1<<24)-1); + dog_toggle(ctl); + dog_pet(ctl); + } else { + gt_wr(GT_WDOG_Config, timeout_us | GT_WDOG_Config_Ctl1a); + gt_wr(GT_WDOG_Config, timeout_us | GT_WDOG_Config_Ctl1b); + } + + wdog_on = GT_WDOG_Config_Enb | timeout_us; + + rtems_interrupt_enable(flags); + return 0; +} + +/* Disable watchdog + * RETURNS 0 on success + */ +int BSP_watchdog_disable(void) +{ +unsigned long flags; +uint32_t ctl; + + rtems_interrupt_disable(flags); + + ctl = rd_wdcnf(); + + if ( (GT_WDOG_Config_Enb & ctl) ) { + dog_toggle(ctl); + wdog_on = ctl & ~(GT_WDOG_Config_Enb); + } + + rtems_interrupt_enable(flags); + return 0; +} + +/* Check status -- unfortunately there seems to be no way + * to read the running value... + * + * RETURNS nonzero if enabled/running, zero if disabled/stopped + */ +int BSP_watchdog_status(void) +{ + uint32_t ctl = rd_wdcnf(); + + /* report also the current period */ + return GT_WDOG_Config_Enb & ctl ? ctl : 0; +} + +/* Pet the watchdog (rearm to configured timeout) + * RETURNS: 0 on success, nonzero on failure (watchdog + * currently not running). + */ +int BSP_watchdog_pet(void) +{ + unsigned long flags; + + if ( !wdog_on ) + return -1; + rtems_interrupt_disable(flags); + dog_pet(rd_wdcnf()); + rtems_interrupt_enable(flags); + return 0; +} + + +#ifdef DEBUG_MODULAR +int +_cexpModuleFinalize(void *unused) +{ + BSP_watchdog_disable(); + return BSP_timers_uninstall(); +} + +void +_cexpModuleInitialize(void *unused) +{ + BSP_timers_initialize(); +} +#endif diff --git a/bsps/powerpc/beatnik/marvell/gti2c.c b/bsps/powerpc/beatnik/marvell/gti2c.c new file mode 100644 index 0000000000..c602bac5eb --- /dev/null +++ b/bsps/powerpc/beatnik/marvell/gti2c.c @@ -0,0 +1,447 @@ +/* $NetBSD: gti2c.c,v 1.2 2005/02/27 00:27:21 perry Exp $ */ + +/* + * Copyright (c) 2005 Brocade Communcations, inc. + * All rights reserved. + * + * Written by Matt Thomas for Brocade Communcations, Inc. + * + * 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. The name of Brocade Communications, Inc. may not be used to endorse + * or promote products derived from this software without specific prior + * written permission. + * + * THIS SOFTWARE IS PROVIDED BY BROCADE COMMUNICATIONS, INC. ``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 EITHER BROCADE COMMUNICATIONS, INC. 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. + */ + +/* Fixed many things + ported to RTEMS by Till Straumann, 2005 */ + +#include <stdio.h> +#include <rtems.h> +#include <libcpu/io.h> +#include <sys/errno.h> +#include <rtems/bspIo.h> +#include <rtems/score/sysstate.h> +#include <bsp/irq.h> +#include <rtems/libi2c.h> + +#include <sys/cdefs.h> + +#include <bsp/gtintrreg.h> +#include <bsp/gti2creg.h> +#include <bsp/gti2c_busdrv.h> + +#define ENABLE_IRQ_AT_PIC_HACK /* workaround for a bad HW bug */ +#undef DEBUG + +#ifndef BSP_IRQ_MIN_PRIO +#define BSP_IRQ_MIN_PRIO 1 +#endif + +struct gti2c_softc { + uint32_t sc_gt; + uint32_t sc_cntl; + int sc_inited; + rtems_id sc_sync; + int sc_irqs; /* statistics */ +}; + +#ifdef DEBUG +#define STATIC +#else +#define STATIC static +#endif + +typedef struct { + rtems_libi2c_bus_t bus_desc; + struct gti2c_softc pvt; +} gti2c_desc_rec, *gti2c_desc; + +STATIC rtems_status_code +gt_i2c_init(rtems_libi2c_bus_t *bh); +STATIC rtems_status_code +gt_i2c_send_start(rtems_libi2c_bus_t *bh); +STATIC rtems_status_code +gt_i2c_send_stop(rtems_libi2c_bus_t *bh); +STATIC rtems_status_code +gt_i2c_send_addr(rtems_libi2c_bus_t *bh, uint32_t addr, int rw); +STATIC int +gt_i2c_read_bytes(rtems_libi2c_bus_t *bh, unsigned char *buf, int len); +STATIC int +gt_i2c_write_bytes(rtems_libi2c_bus_t *bh, unsigned char *buf, int len); + +static rtems_libi2c_bus_ops_t myops = { + init: gt_i2c_init, + send_start: gt_i2c_send_start, + send_stop: gt_i2c_send_stop, + send_addr: gt_i2c_send_addr, + read_bytes: gt_i2c_read_bytes, + write_bytes: gt_i2c_write_bytes, +}; + +static gti2c_desc_rec my_bus_tbl = { + { + ops: &myops, + size: sizeof(my_bus_tbl), + },/* public fields */ + { + sc_gt: BSP_MV64x60_BASE, + sc_cntl: I2C_Control_TWSIEn, + sc_inited: 0, + sc_sync: 0 + } /* our private fields */ +}; + + +static inline uint32_t +gt_read(uint32_t base, uint32_t off) +{ + return in_le32((volatile uint32_t*)(base+off)); +} + +static inline void +gt_write(uint32_t base, uint32_t off, uint32_t val) +{ + out_le32((volatile uint32_t*)(base+off), val); +} + + +static inline void +disable_irq(struct gti2c_softc *sc) +{ +uint32_t v = gt_read(sc->sc_gt, I2C_REG_Control); + gt_write(sc->sc_gt, I2C_REG_Control, v & ~I2C_Control_IntEn); +} + + +static rtems_status_code +gt_i2c_wait(struct gti2c_softc *sc, uint32_t control, uint32_t desired_status) +{ + uint32_t status; + rtems_status_code rval; + + control |= I2C_Control_IntEn; + + gt_write(sc->sc_gt, I2C_REG_Control, control | sc->sc_cntl); + + if ( sc->sc_inited ) { + +#ifdef ENABLE_IRQ_AT_PIC_HACK + BSP_enable_irq_at_pic(BSP_IRQ_I2C); +#endif + + rval = rtems_semaphore_obtain(sc->sc_sync, RTEMS_WAIT, 100); + + if ( RTEMS_SUCCESSFUL != rval ) + return rval; + } else { + uint32_t then, now; + + /* run in polling mode - useful during init */ + if ( _System_state_Is_up(_System_state_Get()) ) { + printk("WARNING: gti2c running in polled mode -- should initialize properly!\n"); + } + + asm volatile("mftb %0":"=r"(then)); + + do { + asm volatile("mftb %0":"=r"(now)); + /* poll timebase for .2 seconds assuming a bus clock of 100MHz */ + if ( now - then > (uint32_t)100000000/4/5 ) + return RTEMS_TIMEOUT; + } while ( ! (I2C_Control_IFlg & gt_read(sc->sc_gt, I2C_REG_Control)) ); + } + + status = gt_read(sc->sc_gt, I2C_REG_Status); + + if ( status != desired_status && (status!=I2C_Status_ReStarted || desired_status!=I2C_Status_Started) ) + return RTEMS_IO_ERROR; + + return RTEMS_SUCCESSFUL; +} + +static void +gt_i2c_intr(void *arg) +{ +struct gti2c_softc * const sc = &my_bus_tbl.pvt; + uint32_t v; + + v = gt_read(sc->sc_gt, I2C_REG_Control); + if ((v & I2C_Control_IFlg) == 0) { + printk("gt_i2c_intr: IRQ but IFlg not set??\n"); + return; + } + gt_write(sc->sc_gt, I2C_REG_Control, v & ~(I2C_Control_IntEn)); +#if 0 + gt_read(sc->sc_gt, I2C_REG_Control); + asm volatile("sync"); +/* This is how bad it is: after turning off the IntEn bit, the line + * still remains asserted! (shame on you.) + * + * The test below (on MVME6100; the MVME5500 has the same problem + * but the main cause register address is different; substitute + * 0xf100000c for 0xf1000c68 on a 5500). + * + * The skew was 101 TB ticks or ~3us (bus freq 133MHz) which + * really sucks. + * + * Therefore, we must disable the interrupt at the PIC + */ +{unsigned from,to; + asm volatile("mftb %0":"=r"(from)); + while ( in_le32((volatile uint32_t*)0xf100000c) & 0x20 ) + ; + asm volatile("mftb %0":"=r"(to)); + printk("I2C IRQ remained asserted for %i TB ticks!\n",to-from); +} +#endif +#ifdef ENABLE_IRQ_AT_PIC_HACK + BSP_disable_irq_at_pic(BSP_IRQ_I2C); +#endif + + sc->sc_irqs++; + + rtems_semaphore_release(sc->sc_sync); +} + +STATIC rtems_status_code +gt_i2c_init(rtems_libi2c_bus_t *bh) +{ +struct gti2c_softc * const sc = &((gti2c_desc)bh)->pvt; +unsigned m,n,N; + + disable_irq(sc); + + /* reset */ + gt_write(sc->sc_gt, I2C_REG_SoftReset, 0); + gt_write(sc->sc_gt, I2C_REG_SlaveAddr, 0); + gt_write(sc->sc_gt, I2C_REG_ExtSlaveAddr, 0); + + /* Set baud rate; I don't know the details + * but have to assume that it has to fit into 7 bits + * (as indicated by some experiment) + */ + n = 0, N=1<<n; + do { + n++, N<<=1; + /* increase 2^n until m becomes small enough */ + m = BSP_bus_frequency / 10 / 62500 / N; + } while ( m > 16 ); + + /* n is at least 1 */ + if ( n > 8 ) { + n = 8; m = 16; /* nothing else we can do */ + } + if ( 0 == m ) + m = 1; /* nothing we can do */ + + gt_write(sc->sc_gt, I2C_REG_BaudRate, I2C_BaudRate(m-1, n-1)); + + if ( !sc->sc_inited ) { + + if ( _System_state_Is_up(_System_state_Get()) ) { + rtems_irq_connect_data ii = { + name: BSP_IRQ_I2C, + hdl: gt_i2c_intr, + on: 0, + off: 0, + isOn: 0 + }; + rtems_status_code err; + /* synchronization semaphore */ + err = rtems_semaphore_create( + rtems_build_name('g','i','2','c'), + 0, + RTEMS_SIMPLE_BINARY_SEMAPHORE | RTEMS_LOCAL, + 0, + &sc->sc_sync); + if ( err ) { + sc->sc_sync = 0; + return err; + } + if ( !BSP_install_rtems_irq_handler(&ii) ) { + fprintf(stderr,"Unable to install interrupt handler\n"); + rtems_semaphore_delete(sc->sc_sync); + return RTEMS_INTERNAL_ERROR; + } + BSP_irq_set_priority(BSP_IRQ_I2C, BSP_IRQ_MIN_PRIO); + sc->sc_inited = 1; + } else { + } + } else { + rtems_semaphore_flush(sc->sc_sync); + } + return RTEMS_SUCCESSFUL; +} + +STATIC rtems_status_code +gt_i2c_send_start(rtems_libi2c_bus_t *bh) +{ +struct gti2c_softc * const sc = &((gti2c_desc)bh)->pvt; + + return gt_i2c_wait(sc, I2C_Control_Start, I2C_Status_Started); +} + +STATIC rtems_status_code +gt_i2c_send_stop(rtems_libi2c_bus_t *bh) +{ +struct gti2c_softc * const sc = &((gti2c_desc)bh)->pvt; +uint32_t data; + + data = gt_read(sc->sc_gt, I2C_REG_Status); + if ( I2C_Status_Started == data || I2C_Status_ReStarted == data ) { + /* According to the spec, a void message (start - stop sequence) + * is illegal and indeed, the chip plays bad tricks with us, i.e., + * sometimes it hangs the bus so that it remains idle forever. + * so we have to address someone... + */ + gt_i2c_send_addr(bh, /*just something... */ 8, 1); + data = gt_read(sc->sc_gt, I2C_REG_Status); + } + + if ( I2C_Status_AddrReadAck == data ) { + /* Another thing: spec says that the master generates stop only after + * not acknowledging the last byte. Again, the chip doesn't like + * to be stopped in this condition - hence we just do it the favor + * and read a single byte... + */ + gt_i2c_read_bytes(bh, (unsigned char *)&data, 1); + } + + gt_write(sc->sc_gt, I2C_REG_Control, I2C_Control_Stop | sc->sc_cntl); + + /* should we poll for idle? There seems to be in IRQ when this completes */ + return RTEMS_SUCCESSFUL; +} + +STATIC rtems_status_code +gt_i2c_send_addr(rtems_libi2c_bus_t *bh, uint32_t addr, int rw) +{ +struct gti2c_softc * const sc = &((gti2c_desc)bh)->pvt; +uint32_t data, wanted_status; +uint8_t read_mask = rw ? 1 : 0; +rtems_status_code error; + + if (read_mask) { + wanted_status = I2C_Status_AddrReadAck; + } else { + wanted_status = I2C_Status_AddrWriteAck; + } + /* + * First byte contains whether this xfer is a read or write. + */ + data = read_mask; + if (addr > 0x7f) { + /* + * If this is a 10bit request, the first address byte is + * 0b11110<b9><b8><r/w>. + */ + data |= 0xf0 | ((addr & 0x300) >> 7); + gt_write(sc->sc_gt, I2C_REG_Data, data); + error = gt_i2c_wait(sc, 0, wanted_status); + if (error) + return error; + /* + * The first address byte has been sent, now to send + * the second one. + */ + if (read_mask) { + wanted_status = I2C_Status_2ndAddrReadAck; + } else { + wanted_status = I2C_Status_2ndAddrWriteAck; + } + data = (uint8_t) addr; + } else { + data |= (addr << 1); + } + + gt_write(sc->sc_gt, I2C_REG_Data, data); + return gt_i2c_wait(sc, 0, wanted_status); +} + +STATIC int +gt_i2c_read_bytes(rtems_libi2c_bus_t *bh, unsigned char *buf, int len) +{ +struct gti2c_softc * const sc = &((gti2c_desc)bh)->pvt; +rtems_status_code error; +register unsigned char *p=buf; + + while ( len-- > 0 ) { + error = gt_i2c_wait( + sc, + len ? I2C_Control_ACK : 0, + len ? I2C_Status_MasterReadAck : I2C_Status_MasterReadNoAck); + if ( error ) { + return -error; + } + *p++ = gt_read(sc->sc_gt, I2C_REG_Data); + } + + return p-buf; +} + +STATIC int +gt_i2c_write_bytes(rtems_libi2c_bus_t *bh, unsigned char *buf, int len) +{ +struct gti2c_softc * const sc = &((gti2c_desc)bh)->pvt; +int rval = 0; +rtems_status_code error; + + while ( len-- > 0 ) { + gt_write(sc->sc_gt, I2C_REG_Data, buf[rval]); + error = gt_i2c_wait(sc, 0, I2C_Status_MasterWriteAck); + if ( error ) { + return -error; + } + rval++; + } + + return rval; +} + +rtems_libi2c_bus_t *gt64260_i2c_bus_descriptor = &my_bus_tbl.bus_desc; + +#ifdef DEBUG_MODULAR + +void +_cexpModuleInitialize(void *arg) +{ + gt_i2c_init(>64260_i2c_bus_descriptor->bus_desc); +} + +int +_cexpModuleFinalize(void * arg) +{ +struct gti2c_softc * const sc = >64260_i2c_bus_descriptor->pvt; + + rtems_irq_connect_data ii = { + name: BSP_IRQ_I2C, + hdl: gt_i2c_intr, + on: noop, + off: noop, + isOn: inoop + }; + + rtems_semaphore_delete(sc->sc_sync); + + return !BSP_remove_rtems_irq_handler(&ii); +} + +#endif diff --git a/bsps/powerpc/beatnik/vme/vme_dma.c b/bsps/powerpc/beatnik/vme/vme_dma.c new file mode 100644 index 0000000000..29ba3e6bfe --- /dev/null +++ b/bsps/powerpc/beatnik/vme/vme_dma.c @@ -0,0 +1,215 @@ +/* Setup/glue to attach VME DMA driver to the beatnik BSP */ + +/* + * Authorship + * ---------- + * This software ('beatnik' RTEMS BSP for MVME6100 and MVME5500) was + * created by Till Straumann <strauman@slac.stanford.edu>, 2005-2007, + * Stanford Linear Accelerator Center, Stanford University. + * + * Acknowledgement of sponsorship + * ------------------------------ + * The 'beatnik' BSP was produced by + * the Stanford Linear Accelerator Center, Stanford University, + * under Contract DE-AC03-76SFO0515 with the Department of Energy. + * + * Government disclaimer of liability + * ---------------------------------- + * Neither the United States nor the United States Department of Energy, + * nor any of their employees, makes any warranty, express or implied, or + * assumes any legal liability or responsibility for the accuracy, + * completeness, or usefulness of any data, apparatus, product, or process + * disclosed, or represents that its use would not infringe privately owned + * rights. + * + * Stanford disclaimer of liability + * -------------------------------- + * Stanford University makes no representations or warranties, express or + * implied, nor assumes any liability for the use of this software. + * + * Stanford disclaimer of copyright + * -------------------------------- + * Stanford University, owner of the copyright, hereby disclaims its + * copyright and all other rights in this software. Hence, anyone may + * freely use it for any purpose without restriction. + * + * Maintenance of notices + * ---------------------- + * In the interest of clarity regarding the origin and status of this + * SLAC software, this and all the preceding Stanford University notices + * are to remain affixed to any copy or derivative of this software made + * or distributed by the recipient and are to be affixed to any copy of + * software made or distributed by the recipient that contains a copy or + * derivative of this software. + * + * ------------------ SLAC Software Notices, Set 4 OTT.002a, 2004 FEB 03 + */ + +#include <stdio.h> +#include <stdint.h> +#include <rtems.h> +#include <bsp.h> +#include <bsp/VME.h> +#include <bsp/vmeTsi148.h> +#include <bsp/vmeUniverse.h> +#include <bsp/VMEDMA.h> +#include <bsp/vmeTsi148DMA.h> +#include <bsp/vmeUniverseDMA.h> +#include <bsp/bspVmeDmaList.h> + +typedef struct DmaOpsRec_ { + int (*setup)(int, uint32_t, uint32_t, void *); + int (*start)(int, uint32_t, uint32_t, uint32_t); + uint32_t (*status)(int); + VMEDmaListClass listClass; +} DmaOpsRec, *DmaOps; + +static DmaOpsRec universeOps = { + vmeUniverseDmaSetup, + vmeUniverseDmaStart, + vmeUniverseDmaStatus, + &vmeUniverseDmaListClass, +}; + +static DmaOpsRec tsiOps = { + vmeTsi148DmaSetup, + vmeTsi148DmaStart, + vmeTsi148DmaStatus, + &vmeTsi148DmaListClass, +}; + +static int setup(int a, uint32_t b, uint32_t c, void *d); +static int start(int a, uint32_t b, uint32_t c, uint32_t d); +static uint32_t status(int a); + +static DmaOpsRec jumpstartOps = { + setup, + start, + status, + 0 +}; + +static DmaOps dmaOps = &jumpstartOps; + +static DmaOps selectOps() +{ + return (MVME6100 != BSP_getBoardType()) ? + &universeOps : &tsiOps; +} + +static int +setup(int a, uint32_t b, uint32_t c, void *d) +{ + return (dmaOps=selectOps())->setup(a,b,c,d); +} + +static int +start(int a, uint32_t b, uint32_t c, uint32_t d) +{ + return (dmaOps=selectOps())->start(a,b,c,d); +} + +static uint32_t +status(int a) +{ + return (dmaOps=selectOps())->status(a); +} + + +int +BSP_VMEDmaSetup(int channel, uint32_t bus_mode, uint32_t xfer_mode, void *custom_setup) +{ + return dmaOps->setup(channel, bus_mode, xfer_mode, custom_setup); +} + +int +BSP_VMEDmaStart(int channel, uint32_t pci_addr, uint32_t vme_addr, uint32_t n_bytes) +{ + return dmaOps->start(channel, pci_addr, vme_addr, n_bytes); +} + +uint32_t +BSP_VMEDmaStatus(int channel) +{ + return dmaOps->status(channel); +} + +BSP_VMEDmaListDescriptor +BSP_VMEDmaListDescriptorSetup( + BSP_VMEDmaListDescriptor d, + uint32_t attr_mask, + uint32_t xfer_mode, + uint32_t pci_addr, + uint32_t vme_addr, + uint32_t n_bytes) +{ +VMEDmaListClass pc; + if ( !d ) { + if ( ! (pc = dmaOps->listClass) ) { + pc = (dmaOps = selectOps())->listClass; + } + return BSP_VMEDmaListDescriptorNewTool( + pc, + attr_mask, + xfer_mode, + pci_addr, + vme_addr, + n_bytes); + + } + return BSP_VMEDmaListDescriptorSetupTool(d, attr_mask, xfer_mode, pci_addr, vme_addr, n_bytes); +} + +int +BSP_VMEDmaListStart(int channel, BSP_VMEDmaListDescriptor list) +{ + return BSP_VMEDmaListDescriptorStartTool(0, channel, list); +} + +/* NOT thread safe! */ +int +BSP_VMEDmaInstallISR(int channel, BSP_VMEDmaIRQCallback cb, void *usr_arg) +{ +int vec; +BSP_VME_ISR_t curr; +void *carg; + + if ( MVME6100 != BSP_getBoardType() ) { + if ( channel != 0 ) + return -1; + + vec = UNIV_DMA_INT_VEC; + + } else { + if ( channel < 0 || channel > 1 ) + return -1; + + vec = (channel ? TSI_DMA1_INT_VEC : TSI_DMA_INT_VEC ); + } + + curr = BSP_getVME_isr(vec, &carg); + + if ( cb && curr ) { + /* IRQ currently in use */ + return -1; + } + + if ( !cb && !curr ) { + /* Allow uninstall if no handler is currently installed; + * just make sure IRQ is disabled + */ + BSP_disableVME_int_lvl(vec); + return 0; + } + + if ( cb ) { + if ( BSP_installVME_isr(vec, (BSP_VME_ISR_t)cb, usr_arg) ) + return -4; + BSP_enableVME_int_lvl(vec); + } else { + BSP_disableVME_int_lvl(vec); + if ( BSP_removeVME_isr(vec, curr, carg) ) + return -4; + } + return 0; +} diff --git a/bsps/powerpc/beatnik/vme/vmeconfig.c b/bsps/powerpc/beatnik/vme/vmeconfig.c new file mode 100644 index 0000000000..383cfc4e96 --- /dev/null +++ b/bsps/powerpc/beatnik/vme/vmeconfig.c @@ -0,0 +1,303 @@ +/* Standard VME bridge configuration for MVME5500, MVME6100 */ + +/* + * Authorship + * ---------- + * This software ('beatnik' RTEMS BSP for MVME6100 and MVME5500) was + * created by Till Straumann <strauman@slac.stanford.edu>, 2005-2007, + * Stanford Linear Accelerator Center, Stanford University. + * + * Acknowledgement of sponsorship + * ------------------------------ + * The 'beatnik' BSP was produced by + * the Stanford Linear Accelerator Center, Stanford University, + * under Contract DE-AC03-76SFO0515 with the Department of Energy. + * + * Government disclaimer of liability + * ---------------------------------- + * Neither the United States nor the United States Department of Energy, + * nor any of their employees, makes any warranty, express or implied, or + * assumes any legal liability or responsibility for the accuracy, + * completeness, or usefulness of any data, apparatus, product, or process + * disclosed, or represents that its use would not infringe privately owned + * rights. + * + * Stanford disclaimer of liability + * -------------------------------- + * Stanford University makes no representations or warranties, express or + * implied, nor assumes any liability for the use of this software. + * + * Stanford disclaimer of copyright + * -------------------------------- + * Stanford University, owner of the copyright, hereby disclaims its + * copyright and all other rights in this software. Hence, anyone may + * freely use it for any purpose without restriction. + * + * Maintenance of notices + * ---------------------- + * In the interest of clarity regarding the origin and status of this + * SLAC software, this and all the preceding Stanford University notices + * are to remain affixed to any copy or derivative of this software made + * or distributed by the recipient and are to be affixed to any copy of + * software made or distributed by the recipient that contains a copy or + * derivative of this software. + * + * ------------------ SLAC Software Notices, Set 4 OTT.002a, 2004 FEB 03 + */ + +#include <rtems.h> +#include <rtems/bspIo.h> +#include <bsp.h> +#include <bsp/VME.h> +#include <bsp/VMEConfig.h> +#include <bsp/irq.h> +#include <bsp/vmeUniverse.h> +#define _VME_TSI148_DECLARE_SHOW_ROUTINES +#include <bsp/vmeTsi148.h> +#include <libcpu/bat.h> + +/* Use a weak alias for the VME configuration. + * This permits individual applications to override + * this routine. + * They may even create an 'empty' + * + * void BSP_vme_config(void) {} + * + * which will avoid linking in the Universe driver + * at all :-). + */ + +void BSP_vme_config(void) __attribute__ (( weak, alias("__BSP_default_vme_config") )); + +typedef struct { + int (*xlate_adrs)(int, int, unsigned long, unsigned long, unsigned long *); + int (*install_isr)(unsigned long, BSP_VME_ISR_t, void *); + int (*remove_isr)(unsigned long, BSP_VME_ISR_t, void *); + BSP_VME_ISR_t (*get_isr)(unsigned long vector, void **); + int (*enable_int_lvl)(unsigned int); + int (*disable_int_lvl)(unsigned int); + int (*outbound_p_cfg)(unsigned long, unsigned long, unsigned long, unsigned long, unsigned long); + int (*inbound_p_cfg) (unsigned long, unsigned long, unsigned long, unsigned long, unsigned long); + void (*outbound_p_show)(FILE*); + void (*inbound_p_show) (FILE*); + void (*reset_bus)(void); + int (*install_irq_mgr)(int, int, int, ...); +} VMEOpsRec, *VMEOps; + +static VMEOpsRec uniOpsRec = { + xlate_adrs: vmeUniverseXlateAddr, + install_isr: vmeUniverseInstallISR, + remove_isr: vmeUniverseRemoveISR, + get_isr: vmeUniverseISRGet, + enable_int_lvl: vmeUniverseIntEnable, + disable_int_lvl: vmeUniverseIntDisable, + outbound_p_cfg: vmeUniverseMasterPortCfg, + inbound_p_cfg: vmeUniverseSlavePortCfg, + outbound_p_show: vmeUniverseMasterPortsShow, + inbound_p_show: vmeUniverseSlavePortsShow, + reset_bus: vmeUniverseResetBus, + install_irq_mgr: vmeUniverseInstallIrqMgrAlt, +}; + +static VMEOpsRec tsiOpsRec = { + xlate_adrs: vmeTsi148XlateAddr, + install_isr: vmeTsi148InstallISR, + remove_isr: vmeTsi148RemoveISR, + get_isr: vmeTsi148ISRGet, + enable_int_lvl: vmeTsi148IntEnable, + disable_int_lvl: vmeTsi148IntDisable, + outbound_p_cfg: vmeTsi148OutboundPortCfg, + inbound_p_cfg: vmeTsi148InboundPortCfg, + outbound_p_show: vmeTsi148OutboundPortsShow, + inbound_p_show: vmeTsi148InboundPortsShow, + reset_bus: vmeTsi148ResetBus, + install_irq_mgr: vmeTsi148InstallIrqMgrAlt, +}; + +static VMEOps theOps = 0; + +int +BSP_vme2local_adrs(unsigned long am, unsigned long vmeaddr, unsigned long *plocaladdr) +{ +int rval=theOps->xlate_adrs(1,0,am,vmeaddr,plocaladdr); + *plocaladdr+=PCI_MEM_BASE; + return rval; +} + +int +BSP_local2vme_adrs(unsigned long am, unsigned long localaddr, unsigned long *pvmeaddr) +{ + return theOps->xlate_adrs(0, 0, am,localaddr+PCI_DRAM_OFFSET,pvmeaddr); +} + +int +BSP_installVME_isr(unsigned long vector, BSP_VME_ISR_t handler, void *arg) +{ + return theOps->install_isr(vector, handler, arg); +} + +int +BSP_removeVME_isr(unsigned long vector, BSP_VME_ISR_t handler, void *arg) +{ + return theOps->remove_isr(vector, handler, arg); +} + +/* retrieve the currently installed ISR for a given vector */ +BSP_VME_ISR_t +BSP_getVME_isr(unsigned long vector, void **parg) +{ + return theOps->get_isr(vector, parg); +} + +int +BSP_enableVME_int_lvl(unsigned int level) +{ + return theOps->enable_int_lvl(level); +} + +int +BSP_disableVME_int_lvl(unsigned int level) +{ + return theOps->disable_int_lvl(level); +} + +int +BSP_VMEOutboundPortCfg( + unsigned long port, + unsigned long address_space, + unsigned long vme_address, + unsigned long pci_address, + unsigned long size) +{ + return theOps->outbound_p_cfg(port, address_space, vme_address, pci_address, size); +} + +int +BSP_VMEInboundPortCfg( + unsigned long port, + unsigned long address_space, + unsigned long vme_address, + unsigned long pci_address, + unsigned long size) +{ + return theOps->inbound_p_cfg(port, address_space, vme_address, pci_address, size); +} + +void +BSP_VMEOutboundPortsShow(FILE *f) +{ + theOps->outbound_p_show(f); +} + +void +BSP_VMEInboundPortsShow(FILE *f) +{ + theOps->inbound_p_show(f); +} + +void +BSP_VMEResetBus(void) +{ + theOps->reset_bus(); +} + +static unsigned short +tsi_clear_errors(int quiet) +{ +unsigned long v; +unsigned short rval; + v = vmeTsi148ClearVMEBusErrors(0); + + /* return bits 8..23 of VEAT; set bit 15 to make sure rval is nonzero on error */ + rval = v ? ((v>>8) & 0xffff) | (1<<15) : 0; + return rval; +} + +void +__BSP_default_vme_config(void) +{ +int err = 1; + if ( 0 == vmeUniverseInit() ) { + theOps = &uniOpsRec; + vmeUniverseReset(); + } else if ( 0 == vmeTsi148Init() ) { + theOps = &tsiOpsRec; + vmeTsi148Reset(); + _BSP_clear_vmebridge_errors = tsi_clear_errors; + } else + return; /* no VME bridge found chip */ + + /* map VME address ranges */ + BSP_VMEOutboundPortCfg( + 0, + VME_AM_EXT_SUP_DATA, + _VME_A32_WIN0_ON_VME, + _VME_A32_WIN0_ON_PCI, + 0x0e000000 + ); + BSP_VMEOutboundPortCfg( + 1, + VME_AM_STD_SUP_DATA, + 0x00000000, + _VME_A24_ON_PCI, + 0x00ff0000); + BSP_VMEOutboundPortCfg( + 2, + VME_AM_SUP_SHORT_IO, + 0x00000000, + _VME_A16_ON_PCI, + 0x00010000); + +#ifdef _VME_CSR_ON_PCI + /* Map VME64 CSR */ + BSP_VMEOutboundPortCfg( + 7, + VME_AM_CSR, + 0, + _VME_CSR_ON_PCI, + 0x01000000); +#endif + +#ifdef _VME_DRAM_OFFSET + /* map our memory to VME */ + BSP_VMEInboundPortCfg( + 0, + VME_AM_EXT_SUP_DATA | VME_AM_IS_MEMORY, + _VME_DRAM_OFFSET, + PCI_DRAM_OFFSET, + BSP_mem_size); +#endif + + /* stdio is not yet initialized; the driver will revert to printk */ + BSP_VMEOutboundPortsShow(0); + BSP_VMEInboundPortsShow(0); + + switch (BSP_getBoardType()) { + case MVME6100: + err = theOps->install_irq_mgr( + VMETSI148_IRQ_MGR_FLAG_SHARED, + 0, BSP_IRQ_GPP_0 + 20, + 1, BSP_IRQ_GPP_0 + 21, + 2, BSP_IRQ_GPP_0 + 22, + 3, BSP_IRQ_GPP_0 + 23, + -1); + break; + + case MVME5500: + err = theOps->install_irq_mgr( + VMEUNIVERSE_IRQ_MGR_FLAG_SHARED | + VMEUNIVERSE_IRQ_MGR_FLAG_PW_WORKAROUND, + 0, BSP_IRQ_GPP_0 + 12, + 1, BSP_IRQ_GPP_0 + 13, + 2, BSP_IRQ_GPP_0 + 14, + 3, BSP_IRQ_GPP_0 + 15, + -1); + break; + + default: + printk("WARNING: unknown board; "); + break; + } + if ( err ) + printk("VME interrupt manager NOT INSTALLED (error: %i)\n", err); +} |