cregit-Linux how code gets into the kernel

Release 4.7 drivers/ssb/driver_mipscore.c

Directory: drivers/ssb
/*
 * 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 <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

#include "ssb_private.h"


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); }

Contributors

PersonTokensPropCommitsCommitProp
michael bueschmichael buesch25100.00%1100.00%
Total25100.00%1100.00%


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

Contributors

PersonTokensPropCommitsCommitProp
michael bueschmichael buesch29100.00%1100.00%
Total29100.00%1100.00%

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; }

Contributors

PersonTokensPropCommitsCommitProp
michael bueschmichael buesch2151.22%150.00%
matthieu castetmatthieu castet2048.78%150.00%
Total41100.00%2100.00%


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; }

Contributors

PersonTokensPropCommitsCommitProp
matthieu castetmatthieu castet7698.70%150.00%
michael bueschmichael buesch11.30%150.00%
Total77100.00%2100.00%

/* 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; }

Contributors

PersonTokensPropCommitsCommitProp
michael bueschmichael buesch10674.13%150.00%
matthieu castetmatthieu castet3725.87%150.00%
Total143100.00%2100.00%


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]); } }

Contributors

PersonTokensPropCommitsCommitProp
michael bueschmichael buesch66100.00%1100.00%
Total66100.00%1100.00%


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); } ssb_dbg("set_irq: core 0x%04x, irq %d => %d\n", dev->id.coreid, oldirq+2, irq+2); }

Contributors

PersonTokensPropCommitsCommitProp
michael bueschmichael buesch15760.38%250.00%
matthieu castetmatthieu castet9235.38%125.00%
joe perchesjoe perches114.23%125.00%
Total260100.00%4100.00%


static void print_irq(struct ssb_device *dev, unsigned int irq) { static const char *irq_name[] = {"2(S)", "3", "4", "5", "6", "D", "I"}; ssb_dbg("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 ? "*" : " "); }

Contributors

PersonTokensPropCommitsCommitProp
joe perchesjoe perches8661.43%150.00%
matthieu castetmatthieu castet5438.57%150.00%
Total140100.00%2100.00%


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)); } }

Contributors

PersonTokensPropCommitsCommitProp
matthieu castetmatthieu castet5798.28%150.00%
michael bueschmichael buesch11.72%150.00%
Total58100.00%2100.00%


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; }

Contributors

PersonTokensPropCommitsCommitProp
michael bueschmichael buesch7490.24%150.00%
hauke mehrtenshauke mehrtens89.76%150.00%
Total82100.00%2100.00%


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: pr_debug("Found serial flash\n"); ssb_sflash_init(&bus->chipco); break; case SSB_CHIPCO_FLASHT_PARA: pr_debug("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; } }

Contributors

PersonTokensPropCommitsCommitProp
rafal mileckirafal milecki16464.57%555.56%
michael bueschmichael buesch6224.41%111.11%
hauke mehrtenshauke mehrtens2811.02%333.33%
Total254100.00%9100.00%


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; }

Contributors

PersonTokensPropCommitsCommitProp
michael bueschmichael buesch13883.64%133.33%
hauke mehrtenshauke mehrtens2716.36%266.67%
Total165100.00%3100.00%


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 */ ssb_dbg("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; } } ssb_dbg("after irq reconfiguration\n"); dump_irq(bus); ssb_mips_serial_init(mcore); ssb_mips_flash_detect(mcore); }

Contributors

PersonTokensPropCommitsCommitProp
michael bueschmichael buesch22475.42%228.57%
matthieu castetmatthieu castet4113.80%114.29%
jochen friedrichjochen friedrich124.04%114.29%
hauke mehrtenshauke mehrtens82.69%114.29%
felix fietkaufelix fietkau82.69%114.29%
joe perchesjoe perches41.35%114.29%
Total297100.00%7100.00%


Overall Contributors

PersonTokensPropCommitsCommitProp
michael bueschmichael buesch95853.82%315.79%
matthieu castetmatthieu castet37821.24%15.26%
rafal mileckirafal milecki25014.04%631.58%
joe perchesjoe perches1015.67%15.26%
hauke mehrtenshauke mehrtens713.99%421.05%
jochen friedrichjochen friedrich120.67%15.26%
felix fietkaufelix fietkau80.45%15.26%
michael buschmichael busch10.06%15.26%
artem bityutskiyartem bityutskiy10.06%15.26%
Total1780100.00%19100.00%
Directory: drivers/ssb
Information contained on this website is for historical information purposes only and does not indicate or represent copyright ownership.
{% endraw %}