root/drivers/sbus/sbus.c

/* [previous][next][first][last][top][bottom][index][help] */

DEFINITIONS

This source file includes following definitions.
  1. fill_sbus_device
  2. sbus_init

   1 /* sbus.c:  SBus support routines.
   2  *
   3  * Copyright (C) 1995 David S. Miller (davem@caip.rutgers.edu)
   4  */
   5 
   6 #include <linux/kernel.h>
   7 #include <linux/malloc.h>
   8 
   9 #include <asm/system.h>
  10 #include <asm/sbus.h>
  11 #include <asm/dma.h>
  12 #include <asm/oplib.h>
  13 
  14 /* This file has been written to be more dynamic and a bit cleaner,
  15  * but it still needs some spring cleaning.
  16  */
  17 
  18 struct linux_sbus *SBus_chain;
  19 
  20 static char lbuf[128];
  21 
  22 /* Perhaps when I figure out more about the iommu we'll put a
  23  * device registration routine here that probe_sbus() calls to
  24  * setup the iommu for each Sbus.
  25  */
  26 
  27 /* We call this for each SBus device, and fill the structure based
  28  * upon the prom device tree.  We return the start of memory after
  29  * the things we have allocated.
  30  */
  31 
  32 /* #define DEBUG_FILL */
  33 void
  34 fill_sbus_device(int nd, struct linux_sbus_device *sbus_dev)
     /* [previous][next][first][last][top][bottom][index][help] */
  35 {
  36         int grrr, len;
  37         unsigned long dev_base_addr, base;
  38 
  39         sbus_dev->prom_node = nd;
  40         prom_getstring(nd, "name", lbuf, sizeof(lbuf));
  41         strcpy(sbus_dev->prom_name, lbuf);
  42 
  43         dev_base_addr = prom_getint(nd, "address");
  44         if(dev_base_addr != -1)
  45                 sbus_dev->sbus_addr = dev_base_addr;
  46 
  47         len = prom_getproperty(nd, "reg", (void *) sbus_dev->reg_addrs,
  48                                sizeof(sbus_dev->reg_addrs));
  49         if(len%sizeof(struct linux_prom_registers)) {
  50                 prom_printf("WHOOPS:  proplen for %s was %d, need multiple of %d\n",
  51                        sbus_dev->prom_name, len,
  52                        (int) sizeof(struct linux_prom_registers));
  53                 panic("fill_sbus_device");
  54         }
  55         sbus_dev->num_registers = (len/sizeof(struct linux_prom_registers));
  56 
  57         base = (unsigned long) sbus_dev->reg_addrs[0].phys_addr;
  58         if(base>=SUN_SBUS_BVADDR || sparc_cpu_model == sun4m) {
  59                 /* Ahh, we can determine the slot and offset */
  60                 sbus_dev->slot = sbus_dev_slot(base);
  61                 sbus_dev->offset = sbus_dev_offset(base);
  62         } else {   /* Grrr, gotta do calculations to fix things up */
  63                 sbus_dev->slot = sbus_dev->reg_addrs[0].which_io;
  64                 sbus_dev->offset = base;
  65                 sbus_dev->reg_addrs[0].phys_addr = 
  66                         (char *) sbus_devaddr(sbus_dev->slot, base);
  67                 for(grrr=1; grrr<sbus_dev->num_registers; grrr++) {
  68                         base = (unsigned long) sbus_dev->reg_addrs[grrr].phys_addr;
  69                         sbus_dev->reg_addrs[grrr].phys_addr = (char *) 
  70                                 sbus_devaddr(sbus_dev->slot, base);
  71                 }
  72                 /* That surely sucked */
  73         }
  74         sbus_dev->sbus_addr = (unsigned long) sbus_dev->reg_addrs[0].phys_addr;
  75 
  76         if(len>(sizeof(struct linux_prom_registers)*PROMREG_MAX)) {
  77                 prom_printf("WHOOPS:  I got too many register addresses for %s  len=%d\n",
  78                        sbus_dev->prom_name, len);
  79                 panic("sbus device register overflow");
  80         }
  81 
  82         len = prom_getproperty(nd, "address", (void *) sbus_dev->sbus_vaddrs,
  83                                sizeof(sbus_dev->sbus_vaddrs));
  84         if(len == -1) len=0;
  85         if(len&3) {
  86                 prom_printf("Grrr, I didn't get a multiple of 4 proplen "
  87                        "for device %s got %d\n", sbus_dev->prom_name, len);
  88                 len=0;
  89         }
  90         sbus_dev->num_vaddrs = (len/4);
  91   
  92         len = prom_getproperty(nd, "intr", (void *)sbus_dev->irqs,
  93                                sizeof(sbus_dev->irqs));
  94         if (len == -1) len=0;
  95         if (len&7) {
  96                 prom_printf("Grrr, I didn't get a multiple of 8 proplen for "
  97                        "device %s got %d\n", sbus_dev->prom_name, len);
  98                 len=0;
  99         }
 100         sbus_dev->num_irqs=(len/8);
 101 #if OLD_STYLE_IRQ
 102         /* Grrr, V3 prom tries to be efficient */
 103         for(len=0; len<sbus_dev->num_irqs; len++) {
 104                 sbus_dev->irqs[len].pri &= 0xf;
 105         }
 106 #endif
 107         if(sbus_dev->num_irqs == 0) sbus_dev->irqs[0].pri=0;
 108 
 109 #ifdef DEBUG_FILL
 110         prom_printf("Found %s at SBUS slot %x offset %08lx irq-level %d\n",
 111                sbus_dev->prom_name, sbus_dev->slot, sbus_dev->offset,
 112                sbus_dev->irqs[0].pri);
 113         prom_printf("Base address %08lx\n", sbus_dev->sbus_addr);
 114         prom_printf("REGISTERS: Probed %d register(s)\n", sbus_dev->num_registers);
 115         for(len=0; len<sbus_dev->num_registers; len++)
 116                 prom_printf("Regs<%d> at address<%08lx> IO-space<%d> size<%d "
 117                        "bytes, %d words>\n", (int) len,
 118                        (unsigned long) sbus_dev->reg_addrs[len].phys_addr,
 119                        sbus_dev->reg_addrs[len].which_io,
 120                        sbus_dev->reg_addrs[len].reg_size,
 121                        (sbus_dev->reg_addrs[len].reg_size/4));
 122 #endif
 123 
 124         return;
 125 }
 126 
 127 /* This routine gets called from whoever needs the sbus first, to scan
 128  * the SBus device tree.  Currently it just prints out the devices
 129  * found on the bus and builds trees of SBUS structs and attached
 130  * devices.
 131  */
 132 
 133 extern void sun_console_init(void);
 134 extern unsigned long iommu_init(int iommu_node, unsigned long memstart,
 135                                 unsigned long memend, struct linux_sbus *sbus);
 136 
 137 unsigned long
 138 sbus_init(unsigned long memory_start, unsigned long memory_end)
     /* [previous][next][first][last][top][bottom][index][help] */
 139 {
 140         register int nd, this_sbus, sbus_devs, topnd, iommund;
 141         unsigned int sbus_clock;
 142         struct linux_sbus *sbus;
 143         struct linux_sbus_device *this_dev;
 144         int num_sbus = 0;  /* How many did we find? */
 145 
 146         memory_start = ((memory_start + 7) & (~7));
 147 
 148         topnd = prom_getchild(prom_root_node);
 149 
 150         /* Finding the first sbus is a special case... */
 151         iommund = 0;
 152         if((nd = prom_searchsiblings(topnd, "sbus")) == 0) {
 153                 if((iommund = prom_searchsiblings(topnd, "iommu")) == 0 ||
 154                    (nd = prom_getchild(iommund)) == 0 ||
 155                    (nd = prom_searchsiblings(nd, "sbus")) == 0) {
 156                         /* No reason to run further - the data access trap will occur. */
 157                         panic("sbus not found");
 158                 }
 159         }
 160 
 161         /* Ok, we've found the first one, allocate first SBus struct
 162          * and place in chain.
 163          */
 164         sbus = SBus_chain = (struct linux_sbus *) memory_start;
 165         memory_start += sizeof(struct linux_sbus);
 166         sbus->next = 0;
 167         this_sbus=nd;
 168 
 169         /* Have IOMMU will travel. XXX grrr - this should be per sbus... */
 170         if(iommund)
 171                 memory_start = iommu_init(iommund, memory_start, memory_end, sbus);
 172 
 173         /* Loop until we find no more SBUS's */
 174         while(this_sbus) {
 175                 printk("sbus%d: ", num_sbus);
 176                 sbus_clock = prom_getint(this_sbus, "clock-frequency");
 177                 if(sbus_clock==-1) sbus_clock = (25*1000*1000);
 178                 printk("Clock %d.%d MHz\n", (int) ((sbus_clock/1000)/1000),
 179                        (int) (((sbus_clock/1000)%1000 != 0) ? 
 180                               (((sbus_clock/1000)%1000) + 1000) : 0));
 181 
 182                 prom_getstring(this_sbus, "name", lbuf, sizeof(lbuf));
 183                 sbus->prom_node = this_sbus;
 184                 strcpy(sbus->prom_name, lbuf);
 185                 sbus->clock_freq = sbus_clock;
 186 
 187                 sbus_devs = prom_getchild(this_sbus);
 188 
 189                 sbus->devices = (struct linux_sbus_device *) memory_start;
 190                 memory_start += sizeof(struct linux_sbus_device);
 191 
 192                 this_dev = sbus->devices;
 193                 this_dev->next = 0;
 194 
 195                 fill_sbus_device(sbus_devs, this_dev);
 196                 this_dev->my_bus = sbus;
 197 
 198                 /* Should we traverse for children? */
 199                 if(strcmp(this_dev->prom_name, "espdma")==0 ||
 200                    strcmp(this_dev->prom_name, "ledma")==0) {
 201                         /* Allocate device node */
 202                         this_dev->child = (struct linux_sbus_device *) memory_start;
 203                         memory_start += sizeof(struct linux_sbus_device);
 204                         /* Fill it */
 205                         fill_sbus_device(prom_getchild(sbus_devs), this_dev->child);
 206                         this_dev->child->my_bus = sbus;
 207                 } else {
 208                         this_dev->child = 0;
 209                 }
 210 
 211                 while((sbus_devs = prom_getsibling(sbus_devs)) != 0) {
 212                         /* Allocate device node */
 213                         this_dev->next = (struct linux_sbus_device *) memory_start;
 214                         memory_start += sizeof(struct linux_sbus_device);
 215                         this_dev=this_dev->next;
 216                         this_dev->next=0;
 217 
 218                         /* Fill it */
 219                         fill_sbus_device(sbus_devs, this_dev);
 220                         this_dev->my_bus = sbus;
 221 
 222                         /* Is there a child node hanging off of us? */
 223                         if(strcmp(this_dev->prom_name, "espdma")==0 ||
 224                            strcmp(this_dev->prom_name, "ledma")==0) {
 225                                 /* Get new device struct */
 226                                 this_dev->child =
 227                                         (struct linux_sbus_device *) memory_start;
 228                                 memory_start += sizeof(struct linux_sbus_device);
 229 
 230                                 /* Fill it */
 231                                 fill_sbus_device(prom_getchild(sbus_devs),
 232                                                  this_dev->child);
 233                                 this_dev->child->my_bus = sbus;
 234                         } else {
 235                                 this_dev->child = 0;
 236                         }
 237                 }
 238 
 239                 memory_start = dvma_init(sbus, memory_start);
 240 
 241                 num_sbus++;
 242                 this_sbus = prom_getsibling(this_sbus);
 243                 if(!this_sbus) break;
 244                 this_sbus = prom_searchsiblings(this_sbus, "sbus");
 245                 if(this_sbus) {
 246                         sbus->next = (struct linux_sbus *) memory_start;
 247                         memory_start += sizeof(struct linux_sbus);
 248                         sbus = sbus->next;
 249                         sbus->next = 0;
 250                 } else {
 251                         break;
 252                 }
 253         } /* while(this_sbus) */
 254         sun_console_init(); /* whee... */
 255         return memory_start;
 256 }

/* [previous][next][first][last][top][bottom][index][help] */