Quellcodebibliothek Statistik Leitseite products/Sources/formale Sprachen/C/Linux/drivers/ssb/   (Open Source Betriebssystem Version 6.17.9©)  Datei vom 24.10.2025 mit Größe 8 kB image not shown  

Quelle  driver_mipscore.c   Sprache: C

 
/*
 * Sonics Silicon Backplane
 * Broadcom MIPS core driver
 *
 * Copyright 2005, Broadcom Corporation
 * Copyright 2006, 2007, Michael Buesch <m@bues.ch>
 *
 * Licensed under the GNU/GPL. See COPYING for details.
 */


#include "ssb_private.h"

#include <linux/ssb/ssb.h>

#include <linux/mtd/physmap.h>
#include <linux/serial.h>
#include <linux/serial_core.h>
#include <linux/serial_reg.h>
#include <linux/time.h>
#ifdef CONFIG_BCM47XX
#include <linux/bcm47xx_nvram.h>
#endif

static const char * const part_probes[] = { "bcm47xxpart", NULL };

static struct physmap_flash_data ssb_pflash_data = {
 .part_probe_types = part_probes,
};

static struct resource ssb_pflash_resource = {
 .name = "ssb_pflash",
 .flags  = IORESOURCE_MEM,
};

struct platform_device ssb_pflash_dev = {
 .name  = "physmap-flash",
 .dev  = {
  .platform_data  = &ssb_pflash_data,
 },
 .resource = &ssb_pflash_resource,
 .num_resources = 1,
};

static inline u32 mips_read32(struct ssb_mipscore *mcore,
         u16 offset)
{
 return ssb_read32(mcore->dev, offset);
}

static inline void mips_write32(struct ssb_mipscore *mcore,
    u16 offset,
    u32 value)
{
 ssb_write32(mcore->dev, offset, value);
}

static const u32 ipsflag_irq_mask[] = {
 0,
 SSB_IPSFLAG_IRQ1,
 SSB_IPSFLAG_IRQ2,
 SSB_IPSFLAG_IRQ3,
 SSB_IPSFLAG_IRQ4,
};

static const u32 ipsflag_irq_shift[] = {
 0,
 SSB_IPSFLAG_IRQ1_SHIFT,
 SSB_IPSFLAG_IRQ2_SHIFT,
 SSB_IPSFLAG_IRQ3_SHIFT,
 SSB_IPSFLAG_IRQ4_SHIFT,
};

static inline u32 ssb_irqflag(struct ssb_device *dev)
{
 u32 tpsflag = ssb_read32(dev, SSB_TPSFLAG);
 if (tpsflag)
  return ssb_read32(dev, SSB_TPSFLAG) & SSB_TPSFLAG_BPFLAG;
 else
  /* not irq supported */
  return 0x3f;
}

static struct ssb_device *find_device(struct ssb_device *rdev, int irqflag)
{
 struct ssb_bus *bus = rdev->bus;
 int i;
 for (i = 0; i < bus->nr_devices; i++) {
  struct ssb_device *dev;
  dev = &(bus->devices[i]);
  if (ssb_irqflag(dev) == irqflag)
   return dev;
 }
 return NULL;
}

/* Get the MIPS IRQ assignment for a specified device.
 * If unassigned, 0 is returned.
 * If disabled, 5 is returned.
 * If not supported, 6 is returned.
 */

unsigned int ssb_mips_irq(struct ssb_device *dev)
{
 struct ssb_bus *bus = dev->bus;
 struct ssb_device *mdev = bus->mipscore.dev;
 u32 irqflag;
 u32 ipsflag;
 u32 tmp;
 unsigned int irq;

 irqflag = ssb_irqflag(dev);
 if (irqflag == 0x3f)
  return 6;
 ipsflag = ssb_read32(bus->mipscore.dev, SSB_IPSFLAG);
 for (irq = 1; irq <= 4; irq++) {
  tmp = ((ipsflag & ipsflag_irq_mask[irq]) >> ipsflag_irq_shift[irq]);
  if (tmp == irqflag)
   break;
 }
 if (irq == 5) {
  if ((1 << irqflag) & ssb_read32(mdev, SSB_INTVEC))
   irq = 0;
 }

 return irq;
}

static void clear_irq(struct ssb_bus *bus, unsigned int irq)
{
 struct ssb_device *dev = bus->mipscore.dev;

 /* Clear the IRQ in the MIPScore backplane registers */
 if (irq == 0) {
  ssb_write32(dev, SSB_INTVEC, 0);
 } else {
  ssb_write32(dev, SSB_IPSFLAG,
       ssb_read32(dev, SSB_IPSFLAG) |
       ipsflag_irq_mask[irq]);
 }
}

static void set_irq(struct ssb_device *dev, unsigned int irq)
{
 unsigned int oldirq = ssb_mips_irq(dev);
 struct ssb_bus *bus = dev->bus;
 struct ssb_device *mdev = bus->mipscore.dev;
 u32 irqflag = ssb_irqflag(dev);

 BUG_ON(oldirq == 6);

 dev->irq = irq + 2;

 /* clear the old irq */
 if (oldirq == 0)
  ssb_write32(mdev, SSB_INTVEC, (~(1 << irqflag) & ssb_read32(mdev, SSB_INTVEC)));
 else if (oldirq != 5)
  clear_irq(bus, oldirq);

 /* assign the new one */
 if (irq == 0) {
  ssb_write32(mdev, SSB_INTVEC, ((1 << irqflag) | ssb_read32(mdev, SSB_INTVEC)));
 } else {
  u32 ipsflag = ssb_read32(mdev, SSB_IPSFLAG);
  if ((ipsflag & ipsflag_irq_mask[irq]) != ipsflag_irq_mask[irq]) {
   u32 oldipsflag = (ipsflag & ipsflag_irq_mask[irq]) >> ipsflag_irq_shift[irq];
   struct ssb_device *olddev = find_device(dev, oldipsflag);
   if (olddev)
    set_irq(olddev, 0);
  }
  irqflag <<= ipsflag_irq_shift[irq];
  irqflag |= (ipsflag & ~ipsflag_irq_mask[irq]);
  ssb_write32(mdev, SSB_IPSFLAG, irqflag);
 }
 dev_dbg(dev->dev, "set_irq: core 0x%04x, irq %d => %d\n",
  dev->id.coreid, oldirq+2, irq+2);
}

static void print_irq(struct ssb_device *dev, unsigned int irq)
{
 static const char *irq_name[] = {"2(S)""3""4""5""6""D""I"};
 dev_dbg(dev->dev,
  "core 0x%04x, irq : %s%s %s%s %s%s %s%s %s%s %s%s %s%s\n",
  dev->id.coreid,
  irq_name[0], irq == 0 ? "*" : " ",
  irq_name[1], irq == 1 ? "*" : " ",
  irq_name[2], irq == 2 ? "*" : " ",
  irq_name[3], irq == 3 ? "*" : " ",
  irq_name[4], irq == 4 ? "*" : " ",
  irq_name[5], irq == 5 ? "*" : " ",
  irq_name[6], irq == 6 ? "*" : " ");
}

static void dump_irq(struct ssb_bus *bus)
{
 int i;
 for (i = 0; i < bus->nr_devices; i++) {
  struct ssb_device *dev;
  dev = &(bus->devices[i]);
  print_irq(dev, ssb_mips_irq(dev));
 }
}

static void ssb_mips_serial_init(struct ssb_mipscore *mcore)
{
 struct ssb_bus *bus = mcore->dev->bus;

 if (ssb_extif_available(&bus->extif))
  mcore->nr_serial_ports = ssb_extif_serial_init(&bus->extif, mcore->serial_ports);
 else if (ssb_chipco_available(&bus->chipco))
  mcore->nr_serial_ports = ssb_chipco_serial_init(&bus->chipco, mcore->serial_ports);
 else
  mcore->nr_serial_ports = 0;
}

static void ssb_mips_flash_detect(struct ssb_mipscore *mcore)
{
 struct ssb_bus *bus = mcore->dev->bus;
 struct ssb_sflash *sflash = &mcore->sflash;
 struct ssb_pflash *pflash = &mcore->pflash;

 /* When there is no chipcommon on the bus there is 4MB flash */
 if (!ssb_chipco_available(&bus->chipco)) {
  pflash->present = true;
  pflash->buswidth = 2;
  pflash->window = SSB_FLASH1;
  pflash->window_size = SSB_FLASH1_SZ;
  goto ssb_pflash;
 }

 /* There is ChipCommon, so use it to read info about flash */
 switch (bus->chipco.capabilities & SSB_CHIPCO_CAP_FLASHT) {
 case SSB_CHIPCO_FLASHT_STSER:
 case SSB_CHIPCO_FLASHT_ATSER:
  dev_dbg(mcore->dev->dev, "Found serial flash\n");
  ssb_sflash_init(&bus->chipco);
  break;
 case SSB_CHIPCO_FLASHT_PARA:
  dev_dbg(mcore->dev->dev, "Found parallel flash\n");
  pflash->present = true;
  pflash->window = SSB_FLASH2;
  pflash->window_size = SSB_FLASH2_SZ;
  if ((ssb_read32(bus->chipco.dev, SSB_CHIPCO_FLASH_CFG)
                 & SSB_CHIPCO_CFG_DS16) == 0)
   pflash->buswidth = 1;
  else
   pflash->buswidth = 2;
  break;
 }

ssb_pflash:
 if (sflash->present) {
#ifdef CONFIG_BCM47XX
  bcm47xx_nvram_init_from_mem(sflash->window, sflash->size);
#endif
 } else if (pflash->present) {
#ifdef CONFIG_BCM47XX
  bcm47xx_nvram_init_from_mem(pflash->window, pflash->window_size);
#endif

  ssb_pflash_data.width = pflash->buswidth;
  ssb_pflash_resource.start = pflash->window;
  ssb_pflash_resource.end = pflash->window + pflash->window_size;
 }
}

u32 ssb_cpu_clock(struct ssb_mipscore *mcore)
{
 struct ssb_bus *bus = mcore->dev->bus;
 u32 pll_type, n, m, rate = 0;

 if (bus->chipco.capabilities & SSB_CHIPCO_CAP_PMU)
  return ssb_pmu_get_cpu_clock(&bus->chipco);

 if (ssb_extif_available(&bus->extif)) {
  ssb_extif_get_clockcontrol(&bus->extif, &pll_type, &n, &m);
 } else if (ssb_chipco_available(&bus->chipco)) {
  ssb_chipco_get_clockcpu(&bus->chipco, &pll_type, &n, &m);
 } else
  return 0;

 if ((pll_type == SSB_PLLTYPE_5) || (bus->chip_id == 0x5365)) {
  rate = 200000000;
 } else {
  rate = ssb_calc_clock_rate(pll_type, n, m);
 }

 if (pll_type == SSB_PLLTYPE_6) {
  rate *= 2;
 }

 return rate;
}

void ssb_mipscore_init(struct ssb_mipscore *mcore)
{
 struct ssb_bus *bus;
 struct ssb_device *dev;
 unsigned long hz, ns;
 unsigned int irq, i;

 if (!mcore->dev)
  return/* We don't have a MIPS core */

 dev_dbg(mcore->dev->dev, "Initializing MIPS core...\n");

 bus = mcore->dev->bus;
 hz = ssb_clockspeed(bus);
 if (!hz)
  hz = 100000000;
 ns = 1000000000 / hz;

 if (ssb_extif_available(&bus->extif))
  ssb_extif_timing_init(&bus->extif, ns);
 else if (ssb_chipco_available(&bus->chipco))
  ssb_chipco_timing_init(&bus->chipco, ns);

 /* Assign IRQs to all cores on the bus, start with irq line 2, because serial usually takes 1 */
 for (irq = 2, i = 0; i < bus->nr_devices; i++) {
  int mips_irq;
  dev = &(bus->devices[i]);
  mips_irq = ssb_mips_irq(dev);
  if (mips_irq > 4)
   dev->irq = 0;
  else
   dev->irq = mips_irq + 2;
  if (dev->irq > 5)
   continue;
  switch (dev->id.coreid) {
  case SSB_DEV_USB11_HOST:
   /* shouldn't need a separate irq line for non-4710, most of them have a proper
 * external usb controller on the pci */

   if ((bus->chip_id == 0x4710) && (irq <= 4)) {
    set_irq(dev, irq++);
   }
   break;
  case SSB_DEV_PCI:
  case SSB_DEV_ETHERNET:
  case SSB_DEV_ETHERNET_GBIT:
  case SSB_DEV_80211:
  case SSB_DEV_USB20_HOST:
   /* These devices get their own IRQ line if available, the rest goes on IRQ0 */
   if (irq <= 4) {
    set_irq(dev, irq++);
    break;
   }
   fallthrough;
  case SSB_DEV_EXTIF:
   set_irq(dev, 0);
   break;
  }
 }
 dev_dbg(mcore->dev->dev, "after irq reconfiguration\n");
 dump_irq(bus);

 ssb_mips_serial_init(mcore);
 ssb_mips_flash_detect(mcore);
}

Messung V0.5
C=96 H=95 G=95

¤ Dauer der Verarbeitung: 0.4 Sekunden  ¤

*© Formatika GbR, Deutschland






Wurzel

Suchen

Beweissystem der NASA

Beweissystem Isabelle

NIST Cobol Testsuite

Cephes Mathematical Library

Wiener Entwicklungsmethode

Haftungshinweis

Die Informationen auf dieser Webseite wurden nach bestem Wissen sorgfältig zusammengestellt. Es wird jedoch weder Vollständigkeit, noch Richtigkeit, noch Qualität der bereit gestellten Informationen zugesichert.

Bemerkung:

Die farbliche Syntaxdarstellung und die Messung sind noch experimentell.