162306a36Sopenharmony_ci/* 262306a36Sopenharmony_ci * Sonics Silicon Backplane 362306a36Sopenharmony_ci * Subsystem core 462306a36Sopenharmony_ci * 562306a36Sopenharmony_ci * Copyright 2005, Broadcom Corporation 662306a36Sopenharmony_ci * Copyright 2006, 2007, Michael Buesch <m@bues.ch> 762306a36Sopenharmony_ci * 862306a36Sopenharmony_ci * Licensed under the GNU/GPL. See COPYING for details. 962306a36Sopenharmony_ci */ 1062306a36Sopenharmony_ci 1162306a36Sopenharmony_ci#include "ssb_private.h" 1262306a36Sopenharmony_ci 1362306a36Sopenharmony_ci#include <linux/delay.h> 1462306a36Sopenharmony_ci#include <linux/io.h> 1562306a36Sopenharmony_ci#include <linux/module.h> 1662306a36Sopenharmony_ci#include <linux/platform_device.h> 1762306a36Sopenharmony_ci#include <linux/ssb/ssb.h> 1862306a36Sopenharmony_ci#include <linux/ssb/ssb_regs.h> 1962306a36Sopenharmony_ci#include <linux/ssb/ssb_driver_gige.h> 2062306a36Sopenharmony_ci#include <linux/dma-mapping.h> 2162306a36Sopenharmony_ci#include <linux/pci.h> 2262306a36Sopenharmony_ci#include <linux/mmc/sdio_func.h> 2362306a36Sopenharmony_ci#include <linux/slab.h> 2462306a36Sopenharmony_ci 2562306a36Sopenharmony_ci#include <pcmcia/cistpl.h> 2662306a36Sopenharmony_ci#include <pcmcia/ds.h> 2762306a36Sopenharmony_ci 2862306a36Sopenharmony_ci 2962306a36Sopenharmony_ciMODULE_DESCRIPTION("Sonics Silicon Backplane driver"); 3062306a36Sopenharmony_ciMODULE_LICENSE("GPL"); 3162306a36Sopenharmony_ci 3262306a36Sopenharmony_ci 3362306a36Sopenharmony_ci/* Temporary list of yet-to-be-attached buses */ 3462306a36Sopenharmony_cistatic LIST_HEAD(attach_queue); 3562306a36Sopenharmony_ci/* List if running buses */ 3662306a36Sopenharmony_cistatic LIST_HEAD(buses); 3762306a36Sopenharmony_ci/* Software ID counter */ 3862306a36Sopenharmony_cistatic unsigned int next_busnumber; 3962306a36Sopenharmony_ci/* buses_mutes locks the two buslists and the next_busnumber. 4062306a36Sopenharmony_ci * Don't lock this directly, but use ssb_buses_[un]lock() below. 4162306a36Sopenharmony_ci */ 4262306a36Sopenharmony_cistatic DEFINE_MUTEX(buses_mutex); 4362306a36Sopenharmony_ci 4462306a36Sopenharmony_ci/* There are differences in the codeflow, if the bus is 4562306a36Sopenharmony_ci * initialized from early boot, as various needed services 4662306a36Sopenharmony_ci * are not available early. This is a mechanism to delay 4762306a36Sopenharmony_ci * these initializations to after early boot has finished. 4862306a36Sopenharmony_ci * It's also used to avoid mutex locking, as that's not 4962306a36Sopenharmony_ci * available and needed early. 5062306a36Sopenharmony_ci */ 5162306a36Sopenharmony_cistatic bool ssb_is_early_boot = 1; 5262306a36Sopenharmony_ci 5362306a36Sopenharmony_cistatic void ssb_buses_lock(void); 5462306a36Sopenharmony_cistatic void ssb_buses_unlock(void); 5562306a36Sopenharmony_ci 5662306a36Sopenharmony_ci 5762306a36Sopenharmony_ci#ifdef CONFIG_SSB_PCIHOST 5862306a36Sopenharmony_cistruct ssb_bus *ssb_pci_dev_to_bus(struct pci_dev *pdev) 5962306a36Sopenharmony_ci{ 6062306a36Sopenharmony_ci struct ssb_bus *bus; 6162306a36Sopenharmony_ci 6262306a36Sopenharmony_ci ssb_buses_lock(); 6362306a36Sopenharmony_ci list_for_each_entry(bus, &buses, list) { 6462306a36Sopenharmony_ci if (bus->bustype == SSB_BUSTYPE_PCI && 6562306a36Sopenharmony_ci bus->host_pci == pdev) 6662306a36Sopenharmony_ci goto found; 6762306a36Sopenharmony_ci } 6862306a36Sopenharmony_ci bus = NULL; 6962306a36Sopenharmony_cifound: 7062306a36Sopenharmony_ci ssb_buses_unlock(); 7162306a36Sopenharmony_ci 7262306a36Sopenharmony_ci return bus; 7362306a36Sopenharmony_ci} 7462306a36Sopenharmony_ci#endif /* CONFIG_SSB_PCIHOST */ 7562306a36Sopenharmony_ci 7662306a36Sopenharmony_ci#ifdef CONFIG_SSB_PCMCIAHOST 7762306a36Sopenharmony_cistruct ssb_bus *ssb_pcmcia_dev_to_bus(struct pcmcia_device *pdev) 7862306a36Sopenharmony_ci{ 7962306a36Sopenharmony_ci struct ssb_bus *bus; 8062306a36Sopenharmony_ci 8162306a36Sopenharmony_ci ssb_buses_lock(); 8262306a36Sopenharmony_ci list_for_each_entry(bus, &buses, list) { 8362306a36Sopenharmony_ci if (bus->bustype == SSB_BUSTYPE_PCMCIA && 8462306a36Sopenharmony_ci bus->host_pcmcia == pdev) 8562306a36Sopenharmony_ci goto found; 8662306a36Sopenharmony_ci } 8762306a36Sopenharmony_ci bus = NULL; 8862306a36Sopenharmony_cifound: 8962306a36Sopenharmony_ci ssb_buses_unlock(); 9062306a36Sopenharmony_ci 9162306a36Sopenharmony_ci return bus; 9262306a36Sopenharmony_ci} 9362306a36Sopenharmony_ci#endif /* CONFIG_SSB_PCMCIAHOST */ 9462306a36Sopenharmony_ci 9562306a36Sopenharmony_ciint ssb_for_each_bus_call(unsigned long data, 9662306a36Sopenharmony_ci int (*func)(struct ssb_bus *bus, unsigned long data)) 9762306a36Sopenharmony_ci{ 9862306a36Sopenharmony_ci struct ssb_bus *bus; 9962306a36Sopenharmony_ci int res; 10062306a36Sopenharmony_ci 10162306a36Sopenharmony_ci ssb_buses_lock(); 10262306a36Sopenharmony_ci list_for_each_entry(bus, &buses, list) { 10362306a36Sopenharmony_ci res = func(bus, data); 10462306a36Sopenharmony_ci if (res >= 0) { 10562306a36Sopenharmony_ci ssb_buses_unlock(); 10662306a36Sopenharmony_ci return res; 10762306a36Sopenharmony_ci } 10862306a36Sopenharmony_ci } 10962306a36Sopenharmony_ci ssb_buses_unlock(); 11062306a36Sopenharmony_ci 11162306a36Sopenharmony_ci return -ENODEV; 11262306a36Sopenharmony_ci} 11362306a36Sopenharmony_ci 11462306a36Sopenharmony_cistatic struct ssb_device *ssb_device_get(struct ssb_device *dev) 11562306a36Sopenharmony_ci{ 11662306a36Sopenharmony_ci if (dev) 11762306a36Sopenharmony_ci get_device(dev->dev); 11862306a36Sopenharmony_ci return dev; 11962306a36Sopenharmony_ci} 12062306a36Sopenharmony_ci 12162306a36Sopenharmony_cistatic void ssb_device_put(struct ssb_device *dev) 12262306a36Sopenharmony_ci{ 12362306a36Sopenharmony_ci if (dev) 12462306a36Sopenharmony_ci put_device(dev->dev); 12562306a36Sopenharmony_ci} 12662306a36Sopenharmony_ci 12762306a36Sopenharmony_cistatic int ssb_device_resume(struct device *dev) 12862306a36Sopenharmony_ci{ 12962306a36Sopenharmony_ci struct ssb_device *ssb_dev = dev_to_ssb_dev(dev); 13062306a36Sopenharmony_ci struct ssb_driver *ssb_drv; 13162306a36Sopenharmony_ci int err = 0; 13262306a36Sopenharmony_ci 13362306a36Sopenharmony_ci if (dev->driver) { 13462306a36Sopenharmony_ci ssb_drv = drv_to_ssb_drv(dev->driver); 13562306a36Sopenharmony_ci if (ssb_drv && ssb_drv->resume) 13662306a36Sopenharmony_ci err = ssb_drv->resume(ssb_dev); 13762306a36Sopenharmony_ci if (err) 13862306a36Sopenharmony_ci goto out; 13962306a36Sopenharmony_ci } 14062306a36Sopenharmony_ciout: 14162306a36Sopenharmony_ci return err; 14262306a36Sopenharmony_ci} 14362306a36Sopenharmony_ci 14462306a36Sopenharmony_cistatic int ssb_device_suspend(struct device *dev, pm_message_t state) 14562306a36Sopenharmony_ci{ 14662306a36Sopenharmony_ci struct ssb_device *ssb_dev = dev_to_ssb_dev(dev); 14762306a36Sopenharmony_ci struct ssb_driver *ssb_drv; 14862306a36Sopenharmony_ci int err = 0; 14962306a36Sopenharmony_ci 15062306a36Sopenharmony_ci if (dev->driver) { 15162306a36Sopenharmony_ci ssb_drv = drv_to_ssb_drv(dev->driver); 15262306a36Sopenharmony_ci if (ssb_drv && ssb_drv->suspend) 15362306a36Sopenharmony_ci err = ssb_drv->suspend(ssb_dev, state); 15462306a36Sopenharmony_ci if (err) 15562306a36Sopenharmony_ci goto out; 15662306a36Sopenharmony_ci } 15762306a36Sopenharmony_ciout: 15862306a36Sopenharmony_ci return err; 15962306a36Sopenharmony_ci} 16062306a36Sopenharmony_ci 16162306a36Sopenharmony_ciint ssb_bus_resume(struct ssb_bus *bus) 16262306a36Sopenharmony_ci{ 16362306a36Sopenharmony_ci int err; 16462306a36Sopenharmony_ci 16562306a36Sopenharmony_ci /* Reset HW state information in memory, so that HW is 16662306a36Sopenharmony_ci * completely reinitialized. 16762306a36Sopenharmony_ci */ 16862306a36Sopenharmony_ci bus->mapped_device = NULL; 16962306a36Sopenharmony_ci#ifdef CONFIG_SSB_DRIVER_PCICORE 17062306a36Sopenharmony_ci bus->pcicore.setup_done = 0; 17162306a36Sopenharmony_ci#endif 17262306a36Sopenharmony_ci 17362306a36Sopenharmony_ci err = ssb_bus_powerup(bus, 0); 17462306a36Sopenharmony_ci if (err) 17562306a36Sopenharmony_ci return err; 17662306a36Sopenharmony_ci err = ssb_pcmcia_hardware_setup(bus); 17762306a36Sopenharmony_ci if (err) { 17862306a36Sopenharmony_ci ssb_bus_may_powerdown(bus); 17962306a36Sopenharmony_ci return err; 18062306a36Sopenharmony_ci } 18162306a36Sopenharmony_ci ssb_chipco_resume(&bus->chipco); 18262306a36Sopenharmony_ci ssb_bus_may_powerdown(bus); 18362306a36Sopenharmony_ci 18462306a36Sopenharmony_ci return 0; 18562306a36Sopenharmony_ci} 18662306a36Sopenharmony_ciEXPORT_SYMBOL(ssb_bus_resume); 18762306a36Sopenharmony_ci 18862306a36Sopenharmony_ciint ssb_bus_suspend(struct ssb_bus *bus) 18962306a36Sopenharmony_ci{ 19062306a36Sopenharmony_ci ssb_chipco_suspend(&bus->chipco); 19162306a36Sopenharmony_ci ssb_pci_xtal(bus, SSB_GPIO_XTAL | SSB_GPIO_PLL, 0); 19262306a36Sopenharmony_ci 19362306a36Sopenharmony_ci return 0; 19462306a36Sopenharmony_ci} 19562306a36Sopenharmony_ciEXPORT_SYMBOL(ssb_bus_suspend); 19662306a36Sopenharmony_ci 19762306a36Sopenharmony_ci#ifdef CONFIG_SSB_SPROM 19862306a36Sopenharmony_ci/** ssb_devices_freeze - Freeze all devices on the bus. 19962306a36Sopenharmony_ci * 20062306a36Sopenharmony_ci * After freezing no device driver will be handling a device 20162306a36Sopenharmony_ci * on this bus anymore. ssb_devices_thaw() must be called after 20262306a36Sopenharmony_ci * a successful freeze to reactivate the devices. 20362306a36Sopenharmony_ci * 20462306a36Sopenharmony_ci * @bus: The bus. 20562306a36Sopenharmony_ci * @ctx: Context structure. Pass this to ssb_devices_thaw(). 20662306a36Sopenharmony_ci */ 20762306a36Sopenharmony_ciint ssb_devices_freeze(struct ssb_bus *bus, struct ssb_freeze_context *ctx) 20862306a36Sopenharmony_ci{ 20962306a36Sopenharmony_ci struct ssb_device *sdev; 21062306a36Sopenharmony_ci struct ssb_driver *sdrv; 21162306a36Sopenharmony_ci unsigned int i; 21262306a36Sopenharmony_ci 21362306a36Sopenharmony_ci memset(ctx, 0, sizeof(*ctx)); 21462306a36Sopenharmony_ci ctx->bus = bus; 21562306a36Sopenharmony_ci WARN_ON(bus->nr_devices > ARRAY_SIZE(ctx->device_frozen)); 21662306a36Sopenharmony_ci 21762306a36Sopenharmony_ci for (i = 0; i < bus->nr_devices; i++) { 21862306a36Sopenharmony_ci sdev = ssb_device_get(&bus->devices[i]); 21962306a36Sopenharmony_ci 22062306a36Sopenharmony_ci if (!sdev->dev || !sdev->dev->driver || 22162306a36Sopenharmony_ci !device_is_registered(sdev->dev)) { 22262306a36Sopenharmony_ci ssb_device_put(sdev); 22362306a36Sopenharmony_ci continue; 22462306a36Sopenharmony_ci } 22562306a36Sopenharmony_ci sdrv = drv_to_ssb_drv(sdev->dev->driver); 22662306a36Sopenharmony_ci if (WARN_ON(!sdrv->remove)) 22762306a36Sopenharmony_ci continue; 22862306a36Sopenharmony_ci sdrv->remove(sdev); 22962306a36Sopenharmony_ci ctx->device_frozen[i] = 1; 23062306a36Sopenharmony_ci } 23162306a36Sopenharmony_ci 23262306a36Sopenharmony_ci return 0; 23362306a36Sopenharmony_ci} 23462306a36Sopenharmony_ci 23562306a36Sopenharmony_ci/** ssb_devices_thaw - Unfreeze all devices on the bus. 23662306a36Sopenharmony_ci * 23762306a36Sopenharmony_ci * This will re-attach the device drivers and re-init the devices. 23862306a36Sopenharmony_ci * 23962306a36Sopenharmony_ci * @ctx: The context structure from ssb_devices_freeze() 24062306a36Sopenharmony_ci */ 24162306a36Sopenharmony_ciint ssb_devices_thaw(struct ssb_freeze_context *ctx) 24262306a36Sopenharmony_ci{ 24362306a36Sopenharmony_ci struct ssb_bus *bus = ctx->bus; 24462306a36Sopenharmony_ci struct ssb_device *sdev; 24562306a36Sopenharmony_ci struct ssb_driver *sdrv; 24662306a36Sopenharmony_ci unsigned int i; 24762306a36Sopenharmony_ci int err, result = 0; 24862306a36Sopenharmony_ci 24962306a36Sopenharmony_ci for (i = 0; i < bus->nr_devices; i++) { 25062306a36Sopenharmony_ci if (!ctx->device_frozen[i]) 25162306a36Sopenharmony_ci continue; 25262306a36Sopenharmony_ci sdev = &bus->devices[i]; 25362306a36Sopenharmony_ci 25462306a36Sopenharmony_ci if (WARN_ON(!sdev->dev || !sdev->dev->driver)) 25562306a36Sopenharmony_ci continue; 25662306a36Sopenharmony_ci sdrv = drv_to_ssb_drv(sdev->dev->driver); 25762306a36Sopenharmony_ci if (WARN_ON(!sdrv || !sdrv->probe)) 25862306a36Sopenharmony_ci continue; 25962306a36Sopenharmony_ci 26062306a36Sopenharmony_ci err = sdrv->probe(sdev, &sdev->id); 26162306a36Sopenharmony_ci if (err) { 26262306a36Sopenharmony_ci dev_err(sdev->dev, 26362306a36Sopenharmony_ci "Failed to thaw device %s\n", 26462306a36Sopenharmony_ci dev_name(sdev->dev)); 26562306a36Sopenharmony_ci result = err; 26662306a36Sopenharmony_ci } 26762306a36Sopenharmony_ci ssb_device_put(sdev); 26862306a36Sopenharmony_ci } 26962306a36Sopenharmony_ci 27062306a36Sopenharmony_ci return result; 27162306a36Sopenharmony_ci} 27262306a36Sopenharmony_ci#endif /* CONFIG_SSB_SPROM */ 27362306a36Sopenharmony_ci 27462306a36Sopenharmony_cistatic void ssb_device_shutdown(struct device *dev) 27562306a36Sopenharmony_ci{ 27662306a36Sopenharmony_ci struct ssb_device *ssb_dev = dev_to_ssb_dev(dev); 27762306a36Sopenharmony_ci struct ssb_driver *ssb_drv; 27862306a36Sopenharmony_ci 27962306a36Sopenharmony_ci if (!dev->driver) 28062306a36Sopenharmony_ci return; 28162306a36Sopenharmony_ci ssb_drv = drv_to_ssb_drv(dev->driver); 28262306a36Sopenharmony_ci if (ssb_drv && ssb_drv->shutdown) 28362306a36Sopenharmony_ci ssb_drv->shutdown(ssb_dev); 28462306a36Sopenharmony_ci} 28562306a36Sopenharmony_ci 28662306a36Sopenharmony_cistatic void ssb_device_remove(struct device *dev) 28762306a36Sopenharmony_ci{ 28862306a36Sopenharmony_ci struct ssb_device *ssb_dev = dev_to_ssb_dev(dev); 28962306a36Sopenharmony_ci struct ssb_driver *ssb_drv = drv_to_ssb_drv(dev->driver); 29062306a36Sopenharmony_ci 29162306a36Sopenharmony_ci if (ssb_drv && ssb_drv->remove) 29262306a36Sopenharmony_ci ssb_drv->remove(ssb_dev); 29362306a36Sopenharmony_ci ssb_device_put(ssb_dev); 29462306a36Sopenharmony_ci} 29562306a36Sopenharmony_ci 29662306a36Sopenharmony_cistatic int ssb_device_probe(struct device *dev) 29762306a36Sopenharmony_ci{ 29862306a36Sopenharmony_ci struct ssb_device *ssb_dev = dev_to_ssb_dev(dev); 29962306a36Sopenharmony_ci struct ssb_driver *ssb_drv = drv_to_ssb_drv(dev->driver); 30062306a36Sopenharmony_ci int err = 0; 30162306a36Sopenharmony_ci 30262306a36Sopenharmony_ci ssb_device_get(ssb_dev); 30362306a36Sopenharmony_ci if (ssb_drv && ssb_drv->probe) 30462306a36Sopenharmony_ci err = ssb_drv->probe(ssb_dev, &ssb_dev->id); 30562306a36Sopenharmony_ci if (err) 30662306a36Sopenharmony_ci ssb_device_put(ssb_dev); 30762306a36Sopenharmony_ci 30862306a36Sopenharmony_ci return err; 30962306a36Sopenharmony_ci} 31062306a36Sopenharmony_ci 31162306a36Sopenharmony_cistatic int ssb_match_devid(const struct ssb_device_id *tabid, 31262306a36Sopenharmony_ci const struct ssb_device_id *devid) 31362306a36Sopenharmony_ci{ 31462306a36Sopenharmony_ci if ((tabid->vendor != devid->vendor) && 31562306a36Sopenharmony_ci tabid->vendor != SSB_ANY_VENDOR) 31662306a36Sopenharmony_ci return 0; 31762306a36Sopenharmony_ci if ((tabid->coreid != devid->coreid) && 31862306a36Sopenharmony_ci tabid->coreid != SSB_ANY_ID) 31962306a36Sopenharmony_ci return 0; 32062306a36Sopenharmony_ci if ((tabid->revision != devid->revision) && 32162306a36Sopenharmony_ci tabid->revision != SSB_ANY_REV) 32262306a36Sopenharmony_ci return 0; 32362306a36Sopenharmony_ci return 1; 32462306a36Sopenharmony_ci} 32562306a36Sopenharmony_ci 32662306a36Sopenharmony_cistatic int ssb_bus_match(struct device *dev, struct device_driver *drv) 32762306a36Sopenharmony_ci{ 32862306a36Sopenharmony_ci struct ssb_device *ssb_dev = dev_to_ssb_dev(dev); 32962306a36Sopenharmony_ci struct ssb_driver *ssb_drv = drv_to_ssb_drv(drv); 33062306a36Sopenharmony_ci const struct ssb_device_id *id; 33162306a36Sopenharmony_ci 33262306a36Sopenharmony_ci for (id = ssb_drv->id_table; 33362306a36Sopenharmony_ci id->vendor || id->coreid || id->revision; 33462306a36Sopenharmony_ci id++) { 33562306a36Sopenharmony_ci if (ssb_match_devid(id, &ssb_dev->id)) 33662306a36Sopenharmony_ci return 1; /* found */ 33762306a36Sopenharmony_ci } 33862306a36Sopenharmony_ci 33962306a36Sopenharmony_ci return 0; 34062306a36Sopenharmony_ci} 34162306a36Sopenharmony_ci 34262306a36Sopenharmony_cistatic int ssb_device_uevent(const struct device *dev, struct kobj_uevent_env *env) 34362306a36Sopenharmony_ci{ 34462306a36Sopenharmony_ci const struct ssb_device *ssb_dev = dev_to_ssb_dev(dev); 34562306a36Sopenharmony_ci 34662306a36Sopenharmony_ci if (!dev) 34762306a36Sopenharmony_ci return -ENODEV; 34862306a36Sopenharmony_ci 34962306a36Sopenharmony_ci return add_uevent_var(env, 35062306a36Sopenharmony_ci "MODALIAS=ssb:v%04Xid%04Xrev%02X", 35162306a36Sopenharmony_ci ssb_dev->id.vendor, ssb_dev->id.coreid, 35262306a36Sopenharmony_ci ssb_dev->id.revision); 35362306a36Sopenharmony_ci} 35462306a36Sopenharmony_ci 35562306a36Sopenharmony_ci#define ssb_config_attr(attrib, field, format_string) \ 35662306a36Sopenharmony_cistatic ssize_t \ 35762306a36Sopenharmony_ciattrib##_show(struct device *dev, struct device_attribute *attr, char *buf) \ 35862306a36Sopenharmony_ci{ \ 35962306a36Sopenharmony_ci return sprintf(buf, format_string, dev_to_ssb_dev(dev)->field); \ 36062306a36Sopenharmony_ci} \ 36162306a36Sopenharmony_cistatic DEVICE_ATTR_RO(attrib); 36262306a36Sopenharmony_ci 36362306a36Sopenharmony_cissb_config_attr(core_num, core_index, "%u\n") 36462306a36Sopenharmony_cissb_config_attr(coreid, id.coreid, "0x%04x\n") 36562306a36Sopenharmony_cissb_config_attr(vendor, id.vendor, "0x%04x\n") 36662306a36Sopenharmony_cissb_config_attr(revision, id.revision, "%u\n") 36762306a36Sopenharmony_cissb_config_attr(irq, irq, "%u\n") 36862306a36Sopenharmony_cistatic ssize_t 36962306a36Sopenharmony_ciname_show(struct device *dev, struct device_attribute *attr, char *buf) 37062306a36Sopenharmony_ci{ 37162306a36Sopenharmony_ci return sprintf(buf, "%s\n", 37262306a36Sopenharmony_ci ssb_core_name(dev_to_ssb_dev(dev)->id.coreid)); 37362306a36Sopenharmony_ci} 37462306a36Sopenharmony_cistatic DEVICE_ATTR_RO(name); 37562306a36Sopenharmony_ci 37662306a36Sopenharmony_cistatic struct attribute *ssb_device_attrs[] = { 37762306a36Sopenharmony_ci &dev_attr_name.attr, 37862306a36Sopenharmony_ci &dev_attr_core_num.attr, 37962306a36Sopenharmony_ci &dev_attr_coreid.attr, 38062306a36Sopenharmony_ci &dev_attr_vendor.attr, 38162306a36Sopenharmony_ci &dev_attr_revision.attr, 38262306a36Sopenharmony_ci &dev_attr_irq.attr, 38362306a36Sopenharmony_ci NULL, 38462306a36Sopenharmony_ci}; 38562306a36Sopenharmony_ciATTRIBUTE_GROUPS(ssb_device); 38662306a36Sopenharmony_ci 38762306a36Sopenharmony_cistatic struct bus_type ssb_bustype = { 38862306a36Sopenharmony_ci .name = "ssb", 38962306a36Sopenharmony_ci .match = ssb_bus_match, 39062306a36Sopenharmony_ci .probe = ssb_device_probe, 39162306a36Sopenharmony_ci .remove = ssb_device_remove, 39262306a36Sopenharmony_ci .shutdown = ssb_device_shutdown, 39362306a36Sopenharmony_ci .suspend = ssb_device_suspend, 39462306a36Sopenharmony_ci .resume = ssb_device_resume, 39562306a36Sopenharmony_ci .uevent = ssb_device_uevent, 39662306a36Sopenharmony_ci .dev_groups = ssb_device_groups, 39762306a36Sopenharmony_ci}; 39862306a36Sopenharmony_ci 39962306a36Sopenharmony_cistatic void ssb_buses_lock(void) 40062306a36Sopenharmony_ci{ 40162306a36Sopenharmony_ci /* See the comment at the ssb_is_early_boot definition */ 40262306a36Sopenharmony_ci if (!ssb_is_early_boot) 40362306a36Sopenharmony_ci mutex_lock(&buses_mutex); 40462306a36Sopenharmony_ci} 40562306a36Sopenharmony_ci 40662306a36Sopenharmony_cistatic void ssb_buses_unlock(void) 40762306a36Sopenharmony_ci{ 40862306a36Sopenharmony_ci /* See the comment at the ssb_is_early_boot definition */ 40962306a36Sopenharmony_ci if (!ssb_is_early_boot) 41062306a36Sopenharmony_ci mutex_unlock(&buses_mutex); 41162306a36Sopenharmony_ci} 41262306a36Sopenharmony_ci 41362306a36Sopenharmony_cistatic void ssb_devices_unregister(struct ssb_bus *bus) 41462306a36Sopenharmony_ci{ 41562306a36Sopenharmony_ci struct ssb_device *sdev; 41662306a36Sopenharmony_ci int i; 41762306a36Sopenharmony_ci 41862306a36Sopenharmony_ci for (i = bus->nr_devices - 1; i >= 0; i--) { 41962306a36Sopenharmony_ci sdev = &(bus->devices[i]); 42062306a36Sopenharmony_ci if (sdev->dev) 42162306a36Sopenharmony_ci device_unregister(sdev->dev); 42262306a36Sopenharmony_ci } 42362306a36Sopenharmony_ci 42462306a36Sopenharmony_ci#ifdef CONFIG_SSB_EMBEDDED 42562306a36Sopenharmony_ci if (bus->bustype == SSB_BUSTYPE_SSB) 42662306a36Sopenharmony_ci platform_device_unregister(bus->watchdog); 42762306a36Sopenharmony_ci#endif 42862306a36Sopenharmony_ci} 42962306a36Sopenharmony_ci 43062306a36Sopenharmony_civoid ssb_bus_unregister(struct ssb_bus *bus) 43162306a36Sopenharmony_ci{ 43262306a36Sopenharmony_ci int err; 43362306a36Sopenharmony_ci 43462306a36Sopenharmony_ci err = ssb_gpio_unregister(bus); 43562306a36Sopenharmony_ci if (err) 43662306a36Sopenharmony_ci pr_debug("Can not unregister GPIO driver: %i\n", err); 43762306a36Sopenharmony_ci 43862306a36Sopenharmony_ci ssb_buses_lock(); 43962306a36Sopenharmony_ci ssb_devices_unregister(bus); 44062306a36Sopenharmony_ci list_del(&bus->list); 44162306a36Sopenharmony_ci ssb_buses_unlock(); 44262306a36Sopenharmony_ci 44362306a36Sopenharmony_ci ssb_pcmcia_exit(bus); 44462306a36Sopenharmony_ci ssb_pci_exit(bus); 44562306a36Sopenharmony_ci ssb_iounmap(bus); 44662306a36Sopenharmony_ci} 44762306a36Sopenharmony_ciEXPORT_SYMBOL(ssb_bus_unregister); 44862306a36Sopenharmony_ci 44962306a36Sopenharmony_cistatic void ssb_release_dev(struct device *dev) 45062306a36Sopenharmony_ci{ 45162306a36Sopenharmony_ci struct __ssb_dev_wrapper *devwrap; 45262306a36Sopenharmony_ci 45362306a36Sopenharmony_ci devwrap = container_of(dev, struct __ssb_dev_wrapper, dev); 45462306a36Sopenharmony_ci kfree(devwrap); 45562306a36Sopenharmony_ci} 45662306a36Sopenharmony_ci 45762306a36Sopenharmony_cistatic int ssb_devices_register(struct ssb_bus *bus) 45862306a36Sopenharmony_ci{ 45962306a36Sopenharmony_ci struct ssb_device *sdev; 46062306a36Sopenharmony_ci struct device *dev; 46162306a36Sopenharmony_ci struct __ssb_dev_wrapper *devwrap; 46262306a36Sopenharmony_ci int i, err = 0; 46362306a36Sopenharmony_ci int dev_idx = 0; 46462306a36Sopenharmony_ci 46562306a36Sopenharmony_ci for (i = 0; i < bus->nr_devices; i++) { 46662306a36Sopenharmony_ci sdev = &(bus->devices[i]); 46762306a36Sopenharmony_ci 46862306a36Sopenharmony_ci /* We don't register SSB-system devices to the kernel, 46962306a36Sopenharmony_ci * as the drivers for them are built into SSB. 47062306a36Sopenharmony_ci */ 47162306a36Sopenharmony_ci switch (sdev->id.coreid) { 47262306a36Sopenharmony_ci case SSB_DEV_CHIPCOMMON: 47362306a36Sopenharmony_ci case SSB_DEV_PCI: 47462306a36Sopenharmony_ci case SSB_DEV_PCIE: 47562306a36Sopenharmony_ci case SSB_DEV_PCMCIA: 47662306a36Sopenharmony_ci case SSB_DEV_MIPS: 47762306a36Sopenharmony_ci case SSB_DEV_MIPS_3302: 47862306a36Sopenharmony_ci case SSB_DEV_EXTIF: 47962306a36Sopenharmony_ci continue; 48062306a36Sopenharmony_ci } 48162306a36Sopenharmony_ci 48262306a36Sopenharmony_ci devwrap = kzalloc(sizeof(*devwrap), GFP_KERNEL); 48362306a36Sopenharmony_ci if (!devwrap) { 48462306a36Sopenharmony_ci err = -ENOMEM; 48562306a36Sopenharmony_ci goto error; 48662306a36Sopenharmony_ci } 48762306a36Sopenharmony_ci dev = &devwrap->dev; 48862306a36Sopenharmony_ci devwrap->sdev = sdev; 48962306a36Sopenharmony_ci 49062306a36Sopenharmony_ci dev->release = ssb_release_dev; 49162306a36Sopenharmony_ci dev->bus = &ssb_bustype; 49262306a36Sopenharmony_ci dev_set_name(dev, "ssb%u:%d", bus->busnumber, dev_idx); 49362306a36Sopenharmony_ci 49462306a36Sopenharmony_ci switch (bus->bustype) { 49562306a36Sopenharmony_ci case SSB_BUSTYPE_PCI: 49662306a36Sopenharmony_ci#ifdef CONFIG_SSB_PCIHOST 49762306a36Sopenharmony_ci sdev->irq = bus->host_pci->irq; 49862306a36Sopenharmony_ci dev->parent = &bus->host_pci->dev; 49962306a36Sopenharmony_ci sdev->dma_dev = dev->parent; 50062306a36Sopenharmony_ci#endif 50162306a36Sopenharmony_ci break; 50262306a36Sopenharmony_ci case SSB_BUSTYPE_PCMCIA: 50362306a36Sopenharmony_ci#ifdef CONFIG_SSB_PCMCIAHOST 50462306a36Sopenharmony_ci sdev->irq = bus->host_pcmcia->irq; 50562306a36Sopenharmony_ci dev->parent = &bus->host_pcmcia->dev; 50662306a36Sopenharmony_ci#endif 50762306a36Sopenharmony_ci break; 50862306a36Sopenharmony_ci case SSB_BUSTYPE_SDIO: 50962306a36Sopenharmony_ci#ifdef CONFIG_SSB_SDIOHOST 51062306a36Sopenharmony_ci dev->parent = &bus->host_sdio->dev; 51162306a36Sopenharmony_ci#endif 51262306a36Sopenharmony_ci break; 51362306a36Sopenharmony_ci case SSB_BUSTYPE_SSB: 51462306a36Sopenharmony_ci dev->dma_mask = &dev->coherent_dma_mask; 51562306a36Sopenharmony_ci sdev->dma_dev = dev; 51662306a36Sopenharmony_ci break; 51762306a36Sopenharmony_ci } 51862306a36Sopenharmony_ci 51962306a36Sopenharmony_ci sdev->dev = dev; 52062306a36Sopenharmony_ci err = device_register(dev); 52162306a36Sopenharmony_ci if (err) { 52262306a36Sopenharmony_ci pr_err("Could not register %s\n", dev_name(dev)); 52362306a36Sopenharmony_ci /* Set dev to NULL to not unregister 52462306a36Sopenharmony_ci * dev on error unwinding. 52562306a36Sopenharmony_ci */ 52662306a36Sopenharmony_ci sdev->dev = NULL; 52762306a36Sopenharmony_ci put_device(dev); 52862306a36Sopenharmony_ci goto error; 52962306a36Sopenharmony_ci } 53062306a36Sopenharmony_ci dev_idx++; 53162306a36Sopenharmony_ci } 53262306a36Sopenharmony_ci 53362306a36Sopenharmony_ci#ifdef CONFIG_SSB_DRIVER_MIPS 53462306a36Sopenharmony_ci if (bus->mipscore.pflash.present) { 53562306a36Sopenharmony_ci err = platform_device_register(&ssb_pflash_dev); 53662306a36Sopenharmony_ci if (err) 53762306a36Sopenharmony_ci pr_err("Error registering parallel flash\n"); 53862306a36Sopenharmony_ci } 53962306a36Sopenharmony_ci#endif 54062306a36Sopenharmony_ci 54162306a36Sopenharmony_ci#ifdef CONFIG_SSB_SFLASH 54262306a36Sopenharmony_ci if (bus->mipscore.sflash.present) { 54362306a36Sopenharmony_ci err = platform_device_register(&ssb_sflash_dev); 54462306a36Sopenharmony_ci if (err) 54562306a36Sopenharmony_ci pr_err("Error registering serial flash\n"); 54662306a36Sopenharmony_ci } 54762306a36Sopenharmony_ci#endif 54862306a36Sopenharmony_ci 54962306a36Sopenharmony_ci return 0; 55062306a36Sopenharmony_cierror: 55162306a36Sopenharmony_ci /* Unwind the already registered devices. */ 55262306a36Sopenharmony_ci ssb_devices_unregister(bus); 55362306a36Sopenharmony_ci return err; 55462306a36Sopenharmony_ci} 55562306a36Sopenharmony_ci 55662306a36Sopenharmony_ci/* Needs ssb_buses_lock() */ 55762306a36Sopenharmony_cistatic int ssb_attach_queued_buses(void) 55862306a36Sopenharmony_ci{ 55962306a36Sopenharmony_ci struct ssb_bus *bus, *n; 56062306a36Sopenharmony_ci int err = 0; 56162306a36Sopenharmony_ci int drop_them_all = 0; 56262306a36Sopenharmony_ci 56362306a36Sopenharmony_ci list_for_each_entry_safe(bus, n, &attach_queue, list) { 56462306a36Sopenharmony_ci if (drop_them_all) { 56562306a36Sopenharmony_ci list_del(&bus->list); 56662306a36Sopenharmony_ci continue; 56762306a36Sopenharmony_ci } 56862306a36Sopenharmony_ci /* Can't init the PCIcore in ssb_bus_register(), as that 56962306a36Sopenharmony_ci * is too early in boot for embedded systems 57062306a36Sopenharmony_ci * (no udelay() available). So do it here in attach stage. 57162306a36Sopenharmony_ci */ 57262306a36Sopenharmony_ci err = ssb_bus_powerup(bus, 0); 57362306a36Sopenharmony_ci if (err) 57462306a36Sopenharmony_ci goto error; 57562306a36Sopenharmony_ci ssb_pcicore_init(&bus->pcicore); 57662306a36Sopenharmony_ci if (bus->bustype == SSB_BUSTYPE_SSB) 57762306a36Sopenharmony_ci ssb_watchdog_register(bus); 57862306a36Sopenharmony_ci 57962306a36Sopenharmony_ci err = ssb_gpio_init(bus); 58062306a36Sopenharmony_ci if (err == -ENOTSUPP) 58162306a36Sopenharmony_ci pr_debug("GPIO driver not activated\n"); 58262306a36Sopenharmony_ci else if (err) 58362306a36Sopenharmony_ci pr_debug("Error registering GPIO driver: %i\n", err); 58462306a36Sopenharmony_ci 58562306a36Sopenharmony_ci ssb_bus_may_powerdown(bus); 58662306a36Sopenharmony_ci 58762306a36Sopenharmony_ci err = ssb_devices_register(bus); 58862306a36Sopenharmony_cierror: 58962306a36Sopenharmony_ci if (err) { 59062306a36Sopenharmony_ci drop_them_all = 1; 59162306a36Sopenharmony_ci list_del(&bus->list); 59262306a36Sopenharmony_ci continue; 59362306a36Sopenharmony_ci } 59462306a36Sopenharmony_ci list_move_tail(&bus->list, &buses); 59562306a36Sopenharmony_ci } 59662306a36Sopenharmony_ci 59762306a36Sopenharmony_ci return err; 59862306a36Sopenharmony_ci} 59962306a36Sopenharmony_ci 60062306a36Sopenharmony_cistatic int ssb_fetch_invariants(struct ssb_bus *bus, 60162306a36Sopenharmony_ci ssb_invariants_func_t get_invariants) 60262306a36Sopenharmony_ci{ 60362306a36Sopenharmony_ci struct ssb_init_invariants iv; 60462306a36Sopenharmony_ci int err; 60562306a36Sopenharmony_ci 60662306a36Sopenharmony_ci memset(&iv, 0, sizeof(iv)); 60762306a36Sopenharmony_ci err = get_invariants(bus, &iv); 60862306a36Sopenharmony_ci if (err) 60962306a36Sopenharmony_ci goto out; 61062306a36Sopenharmony_ci memcpy(&bus->boardinfo, &iv.boardinfo, sizeof(iv.boardinfo)); 61162306a36Sopenharmony_ci memcpy(&bus->sprom, &iv.sprom, sizeof(iv.sprom)); 61262306a36Sopenharmony_ci bus->has_cardbus_slot = iv.has_cardbus_slot; 61362306a36Sopenharmony_ciout: 61462306a36Sopenharmony_ci return err; 61562306a36Sopenharmony_ci} 61662306a36Sopenharmony_ci 61762306a36Sopenharmony_cistatic int __maybe_unused 61862306a36Sopenharmony_cissb_bus_register(struct ssb_bus *bus, 61962306a36Sopenharmony_ci ssb_invariants_func_t get_invariants, 62062306a36Sopenharmony_ci unsigned long baseaddr) 62162306a36Sopenharmony_ci{ 62262306a36Sopenharmony_ci int err; 62362306a36Sopenharmony_ci 62462306a36Sopenharmony_ci spin_lock_init(&bus->bar_lock); 62562306a36Sopenharmony_ci INIT_LIST_HEAD(&bus->list); 62662306a36Sopenharmony_ci#ifdef CONFIG_SSB_EMBEDDED 62762306a36Sopenharmony_ci spin_lock_init(&bus->gpio_lock); 62862306a36Sopenharmony_ci#endif 62962306a36Sopenharmony_ci 63062306a36Sopenharmony_ci /* Powerup the bus */ 63162306a36Sopenharmony_ci err = ssb_pci_xtal(bus, SSB_GPIO_XTAL | SSB_GPIO_PLL, 1); 63262306a36Sopenharmony_ci if (err) 63362306a36Sopenharmony_ci goto out; 63462306a36Sopenharmony_ci 63562306a36Sopenharmony_ci /* Init SDIO-host device (if any), before the scan */ 63662306a36Sopenharmony_ci err = ssb_sdio_init(bus); 63762306a36Sopenharmony_ci if (err) 63862306a36Sopenharmony_ci goto err_disable_xtal; 63962306a36Sopenharmony_ci 64062306a36Sopenharmony_ci ssb_buses_lock(); 64162306a36Sopenharmony_ci bus->busnumber = next_busnumber; 64262306a36Sopenharmony_ci /* Scan for devices (cores) */ 64362306a36Sopenharmony_ci err = ssb_bus_scan(bus, baseaddr); 64462306a36Sopenharmony_ci if (err) 64562306a36Sopenharmony_ci goto err_sdio_exit; 64662306a36Sopenharmony_ci 64762306a36Sopenharmony_ci /* Init PCI-host device (if any) */ 64862306a36Sopenharmony_ci err = ssb_pci_init(bus); 64962306a36Sopenharmony_ci if (err) 65062306a36Sopenharmony_ci goto err_unmap; 65162306a36Sopenharmony_ci /* Init PCMCIA-host device (if any) */ 65262306a36Sopenharmony_ci err = ssb_pcmcia_init(bus); 65362306a36Sopenharmony_ci if (err) 65462306a36Sopenharmony_ci goto err_pci_exit; 65562306a36Sopenharmony_ci 65662306a36Sopenharmony_ci /* Initialize basic system devices (if available) */ 65762306a36Sopenharmony_ci err = ssb_bus_powerup(bus, 0); 65862306a36Sopenharmony_ci if (err) 65962306a36Sopenharmony_ci goto err_pcmcia_exit; 66062306a36Sopenharmony_ci ssb_chipcommon_init(&bus->chipco); 66162306a36Sopenharmony_ci ssb_extif_init(&bus->extif); 66262306a36Sopenharmony_ci ssb_mipscore_init(&bus->mipscore); 66362306a36Sopenharmony_ci err = ssb_fetch_invariants(bus, get_invariants); 66462306a36Sopenharmony_ci if (err) { 66562306a36Sopenharmony_ci ssb_bus_may_powerdown(bus); 66662306a36Sopenharmony_ci goto err_pcmcia_exit; 66762306a36Sopenharmony_ci } 66862306a36Sopenharmony_ci ssb_bus_may_powerdown(bus); 66962306a36Sopenharmony_ci 67062306a36Sopenharmony_ci /* Queue it for attach. 67162306a36Sopenharmony_ci * See the comment at the ssb_is_early_boot definition. 67262306a36Sopenharmony_ci */ 67362306a36Sopenharmony_ci list_add_tail(&bus->list, &attach_queue); 67462306a36Sopenharmony_ci if (!ssb_is_early_boot) { 67562306a36Sopenharmony_ci /* This is not early boot, so we must attach the bus now */ 67662306a36Sopenharmony_ci err = ssb_attach_queued_buses(); 67762306a36Sopenharmony_ci if (err) 67862306a36Sopenharmony_ci goto err_dequeue; 67962306a36Sopenharmony_ci } 68062306a36Sopenharmony_ci next_busnumber++; 68162306a36Sopenharmony_ci ssb_buses_unlock(); 68262306a36Sopenharmony_ci 68362306a36Sopenharmony_ciout: 68462306a36Sopenharmony_ci return err; 68562306a36Sopenharmony_ci 68662306a36Sopenharmony_cierr_dequeue: 68762306a36Sopenharmony_ci list_del(&bus->list); 68862306a36Sopenharmony_cierr_pcmcia_exit: 68962306a36Sopenharmony_ci ssb_pcmcia_exit(bus); 69062306a36Sopenharmony_cierr_pci_exit: 69162306a36Sopenharmony_ci ssb_pci_exit(bus); 69262306a36Sopenharmony_cierr_unmap: 69362306a36Sopenharmony_ci ssb_iounmap(bus); 69462306a36Sopenharmony_cierr_sdio_exit: 69562306a36Sopenharmony_ci ssb_sdio_exit(bus); 69662306a36Sopenharmony_cierr_disable_xtal: 69762306a36Sopenharmony_ci ssb_buses_unlock(); 69862306a36Sopenharmony_ci ssb_pci_xtal(bus, SSB_GPIO_XTAL | SSB_GPIO_PLL, 0); 69962306a36Sopenharmony_ci return err; 70062306a36Sopenharmony_ci} 70162306a36Sopenharmony_ci 70262306a36Sopenharmony_ci#ifdef CONFIG_SSB_PCIHOST 70362306a36Sopenharmony_ciint ssb_bus_pcibus_register(struct ssb_bus *bus, struct pci_dev *host_pci) 70462306a36Sopenharmony_ci{ 70562306a36Sopenharmony_ci int err; 70662306a36Sopenharmony_ci 70762306a36Sopenharmony_ci bus->bustype = SSB_BUSTYPE_PCI; 70862306a36Sopenharmony_ci bus->host_pci = host_pci; 70962306a36Sopenharmony_ci bus->ops = &ssb_pci_ops; 71062306a36Sopenharmony_ci 71162306a36Sopenharmony_ci err = ssb_bus_register(bus, ssb_pci_get_invariants, 0); 71262306a36Sopenharmony_ci if (!err) { 71362306a36Sopenharmony_ci dev_info(&host_pci->dev, 71462306a36Sopenharmony_ci "Sonics Silicon Backplane found on PCI device %s\n", 71562306a36Sopenharmony_ci dev_name(&host_pci->dev)); 71662306a36Sopenharmony_ci } else { 71762306a36Sopenharmony_ci dev_err(&host_pci->dev, 71862306a36Sopenharmony_ci "Failed to register PCI version of SSB with error %d\n", 71962306a36Sopenharmony_ci err); 72062306a36Sopenharmony_ci } 72162306a36Sopenharmony_ci 72262306a36Sopenharmony_ci return err; 72362306a36Sopenharmony_ci} 72462306a36Sopenharmony_ci#endif /* CONFIG_SSB_PCIHOST */ 72562306a36Sopenharmony_ci 72662306a36Sopenharmony_ci#ifdef CONFIG_SSB_PCMCIAHOST 72762306a36Sopenharmony_ciint ssb_bus_pcmciabus_register(struct ssb_bus *bus, 72862306a36Sopenharmony_ci struct pcmcia_device *pcmcia_dev, 72962306a36Sopenharmony_ci unsigned long baseaddr) 73062306a36Sopenharmony_ci{ 73162306a36Sopenharmony_ci int err; 73262306a36Sopenharmony_ci 73362306a36Sopenharmony_ci bus->bustype = SSB_BUSTYPE_PCMCIA; 73462306a36Sopenharmony_ci bus->host_pcmcia = pcmcia_dev; 73562306a36Sopenharmony_ci bus->ops = &ssb_pcmcia_ops; 73662306a36Sopenharmony_ci 73762306a36Sopenharmony_ci err = ssb_bus_register(bus, ssb_pcmcia_get_invariants, baseaddr); 73862306a36Sopenharmony_ci if (!err) { 73962306a36Sopenharmony_ci dev_info(&pcmcia_dev->dev, 74062306a36Sopenharmony_ci "Sonics Silicon Backplane found on PCMCIA device %s\n", 74162306a36Sopenharmony_ci pcmcia_dev->devname); 74262306a36Sopenharmony_ci } 74362306a36Sopenharmony_ci 74462306a36Sopenharmony_ci return err; 74562306a36Sopenharmony_ci} 74662306a36Sopenharmony_ci#endif /* CONFIG_SSB_PCMCIAHOST */ 74762306a36Sopenharmony_ci 74862306a36Sopenharmony_ci#ifdef CONFIG_SSB_SDIOHOST 74962306a36Sopenharmony_ciint ssb_bus_sdiobus_register(struct ssb_bus *bus, struct sdio_func *func, 75062306a36Sopenharmony_ci unsigned int quirks) 75162306a36Sopenharmony_ci{ 75262306a36Sopenharmony_ci int err; 75362306a36Sopenharmony_ci 75462306a36Sopenharmony_ci bus->bustype = SSB_BUSTYPE_SDIO; 75562306a36Sopenharmony_ci bus->host_sdio = func; 75662306a36Sopenharmony_ci bus->ops = &ssb_sdio_ops; 75762306a36Sopenharmony_ci bus->quirks = quirks; 75862306a36Sopenharmony_ci 75962306a36Sopenharmony_ci err = ssb_bus_register(bus, ssb_sdio_get_invariants, ~0); 76062306a36Sopenharmony_ci if (!err) { 76162306a36Sopenharmony_ci dev_info(&func->dev, 76262306a36Sopenharmony_ci "Sonics Silicon Backplane found on SDIO device %s\n", 76362306a36Sopenharmony_ci sdio_func_id(func)); 76462306a36Sopenharmony_ci } 76562306a36Sopenharmony_ci 76662306a36Sopenharmony_ci return err; 76762306a36Sopenharmony_ci} 76862306a36Sopenharmony_ciEXPORT_SYMBOL(ssb_bus_sdiobus_register); 76962306a36Sopenharmony_ci#endif /* CONFIG_SSB_PCMCIAHOST */ 77062306a36Sopenharmony_ci 77162306a36Sopenharmony_ci#ifdef CONFIG_SSB_HOST_SOC 77262306a36Sopenharmony_ciint ssb_bus_host_soc_register(struct ssb_bus *bus, unsigned long baseaddr) 77362306a36Sopenharmony_ci{ 77462306a36Sopenharmony_ci int err; 77562306a36Sopenharmony_ci 77662306a36Sopenharmony_ci bus->bustype = SSB_BUSTYPE_SSB; 77762306a36Sopenharmony_ci bus->ops = &ssb_host_soc_ops; 77862306a36Sopenharmony_ci 77962306a36Sopenharmony_ci err = ssb_bus_register(bus, ssb_host_soc_get_invariants, baseaddr); 78062306a36Sopenharmony_ci if (!err) { 78162306a36Sopenharmony_ci pr_info("Sonics Silicon Backplane found at address 0x%08lX\n", 78262306a36Sopenharmony_ci baseaddr); 78362306a36Sopenharmony_ci } 78462306a36Sopenharmony_ci 78562306a36Sopenharmony_ci return err; 78662306a36Sopenharmony_ci} 78762306a36Sopenharmony_ci#endif 78862306a36Sopenharmony_ci 78962306a36Sopenharmony_ciint __ssb_driver_register(struct ssb_driver *drv, struct module *owner) 79062306a36Sopenharmony_ci{ 79162306a36Sopenharmony_ci drv->drv.name = drv->name; 79262306a36Sopenharmony_ci drv->drv.bus = &ssb_bustype; 79362306a36Sopenharmony_ci drv->drv.owner = owner; 79462306a36Sopenharmony_ci 79562306a36Sopenharmony_ci return driver_register(&drv->drv); 79662306a36Sopenharmony_ci} 79762306a36Sopenharmony_ciEXPORT_SYMBOL(__ssb_driver_register); 79862306a36Sopenharmony_ci 79962306a36Sopenharmony_civoid ssb_driver_unregister(struct ssb_driver *drv) 80062306a36Sopenharmony_ci{ 80162306a36Sopenharmony_ci driver_unregister(&drv->drv); 80262306a36Sopenharmony_ci} 80362306a36Sopenharmony_ciEXPORT_SYMBOL(ssb_driver_unregister); 80462306a36Sopenharmony_ci 80562306a36Sopenharmony_civoid ssb_set_devtypedata(struct ssb_device *dev, void *data) 80662306a36Sopenharmony_ci{ 80762306a36Sopenharmony_ci struct ssb_bus *bus = dev->bus; 80862306a36Sopenharmony_ci struct ssb_device *ent; 80962306a36Sopenharmony_ci int i; 81062306a36Sopenharmony_ci 81162306a36Sopenharmony_ci for (i = 0; i < bus->nr_devices; i++) { 81262306a36Sopenharmony_ci ent = &(bus->devices[i]); 81362306a36Sopenharmony_ci if (ent->id.vendor != dev->id.vendor) 81462306a36Sopenharmony_ci continue; 81562306a36Sopenharmony_ci if (ent->id.coreid != dev->id.coreid) 81662306a36Sopenharmony_ci continue; 81762306a36Sopenharmony_ci 81862306a36Sopenharmony_ci ent->devtypedata = data; 81962306a36Sopenharmony_ci } 82062306a36Sopenharmony_ci} 82162306a36Sopenharmony_ciEXPORT_SYMBOL(ssb_set_devtypedata); 82262306a36Sopenharmony_ci 82362306a36Sopenharmony_cistatic u32 clkfactor_f6_resolve(u32 v) 82462306a36Sopenharmony_ci{ 82562306a36Sopenharmony_ci /* map the magic values */ 82662306a36Sopenharmony_ci switch (v) { 82762306a36Sopenharmony_ci case SSB_CHIPCO_CLK_F6_2: 82862306a36Sopenharmony_ci return 2; 82962306a36Sopenharmony_ci case SSB_CHIPCO_CLK_F6_3: 83062306a36Sopenharmony_ci return 3; 83162306a36Sopenharmony_ci case SSB_CHIPCO_CLK_F6_4: 83262306a36Sopenharmony_ci return 4; 83362306a36Sopenharmony_ci case SSB_CHIPCO_CLK_F6_5: 83462306a36Sopenharmony_ci return 5; 83562306a36Sopenharmony_ci case SSB_CHIPCO_CLK_F6_6: 83662306a36Sopenharmony_ci return 6; 83762306a36Sopenharmony_ci case SSB_CHIPCO_CLK_F6_7: 83862306a36Sopenharmony_ci return 7; 83962306a36Sopenharmony_ci } 84062306a36Sopenharmony_ci return 0; 84162306a36Sopenharmony_ci} 84262306a36Sopenharmony_ci 84362306a36Sopenharmony_ci/* Calculate the speed the backplane would run at a given set of clockcontrol values */ 84462306a36Sopenharmony_ciu32 ssb_calc_clock_rate(u32 plltype, u32 n, u32 m) 84562306a36Sopenharmony_ci{ 84662306a36Sopenharmony_ci u32 n1, n2, clock, m1, m2, m3, mc; 84762306a36Sopenharmony_ci 84862306a36Sopenharmony_ci n1 = (n & SSB_CHIPCO_CLK_N1); 84962306a36Sopenharmony_ci n2 = ((n & SSB_CHIPCO_CLK_N2) >> SSB_CHIPCO_CLK_N2_SHIFT); 85062306a36Sopenharmony_ci 85162306a36Sopenharmony_ci switch (plltype) { 85262306a36Sopenharmony_ci case SSB_PLLTYPE_6: /* 100/200 or 120/240 only */ 85362306a36Sopenharmony_ci if (m & SSB_CHIPCO_CLK_T6_MMASK) 85462306a36Sopenharmony_ci return SSB_CHIPCO_CLK_T6_M1; 85562306a36Sopenharmony_ci return SSB_CHIPCO_CLK_T6_M0; 85662306a36Sopenharmony_ci case SSB_PLLTYPE_1: /* 48Mhz base, 3 dividers */ 85762306a36Sopenharmony_ci case SSB_PLLTYPE_3: /* 25Mhz, 2 dividers */ 85862306a36Sopenharmony_ci case SSB_PLLTYPE_4: /* 48Mhz, 4 dividers */ 85962306a36Sopenharmony_ci case SSB_PLLTYPE_7: /* 25Mhz, 4 dividers */ 86062306a36Sopenharmony_ci n1 = clkfactor_f6_resolve(n1); 86162306a36Sopenharmony_ci n2 += SSB_CHIPCO_CLK_F5_BIAS; 86262306a36Sopenharmony_ci break; 86362306a36Sopenharmony_ci case SSB_PLLTYPE_2: /* 48Mhz, 4 dividers */ 86462306a36Sopenharmony_ci n1 += SSB_CHIPCO_CLK_T2_BIAS; 86562306a36Sopenharmony_ci n2 += SSB_CHIPCO_CLK_T2_BIAS; 86662306a36Sopenharmony_ci WARN_ON(!((n1 >= 2) && (n1 <= 7))); 86762306a36Sopenharmony_ci WARN_ON(!((n2 >= 5) && (n2 <= 23))); 86862306a36Sopenharmony_ci break; 86962306a36Sopenharmony_ci case SSB_PLLTYPE_5: /* 25Mhz, 4 dividers */ 87062306a36Sopenharmony_ci return 100000000; 87162306a36Sopenharmony_ci default: 87262306a36Sopenharmony_ci WARN_ON(1); 87362306a36Sopenharmony_ci } 87462306a36Sopenharmony_ci 87562306a36Sopenharmony_ci switch (plltype) { 87662306a36Sopenharmony_ci case SSB_PLLTYPE_3: /* 25Mhz, 2 dividers */ 87762306a36Sopenharmony_ci case SSB_PLLTYPE_7: /* 25Mhz, 4 dividers */ 87862306a36Sopenharmony_ci clock = SSB_CHIPCO_CLK_BASE2 * n1 * n2; 87962306a36Sopenharmony_ci break; 88062306a36Sopenharmony_ci default: 88162306a36Sopenharmony_ci clock = SSB_CHIPCO_CLK_BASE1 * n1 * n2; 88262306a36Sopenharmony_ci } 88362306a36Sopenharmony_ci if (!clock) 88462306a36Sopenharmony_ci return 0; 88562306a36Sopenharmony_ci 88662306a36Sopenharmony_ci m1 = (m & SSB_CHIPCO_CLK_M1); 88762306a36Sopenharmony_ci m2 = ((m & SSB_CHIPCO_CLK_M2) >> SSB_CHIPCO_CLK_M2_SHIFT); 88862306a36Sopenharmony_ci m3 = ((m & SSB_CHIPCO_CLK_M3) >> SSB_CHIPCO_CLK_M3_SHIFT); 88962306a36Sopenharmony_ci mc = ((m & SSB_CHIPCO_CLK_MC) >> SSB_CHIPCO_CLK_MC_SHIFT); 89062306a36Sopenharmony_ci 89162306a36Sopenharmony_ci switch (plltype) { 89262306a36Sopenharmony_ci case SSB_PLLTYPE_1: /* 48Mhz base, 3 dividers */ 89362306a36Sopenharmony_ci case SSB_PLLTYPE_3: /* 25Mhz, 2 dividers */ 89462306a36Sopenharmony_ci case SSB_PLLTYPE_4: /* 48Mhz, 4 dividers */ 89562306a36Sopenharmony_ci case SSB_PLLTYPE_7: /* 25Mhz, 4 dividers */ 89662306a36Sopenharmony_ci m1 = clkfactor_f6_resolve(m1); 89762306a36Sopenharmony_ci if ((plltype == SSB_PLLTYPE_1) || 89862306a36Sopenharmony_ci (plltype == SSB_PLLTYPE_3)) 89962306a36Sopenharmony_ci m2 += SSB_CHIPCO_CLK_F5_BIAS; 90062306a36Sopenharmony_ci else 90162306a36Sopenharmony_ci m2 = clkfactor_f6_resolve(m2); 90262306a36Sopenharmony_ci m3 = clkfactor_f6_resolve(m3); 90362306a36Sopenharmony_ci 90462306a36Sopenharmony_ci switch (mc) { 90562306a36Sopenharmony_ci case SSB_CHIPCO_CLK_MC_BYPASS: 90662306a36Sopenharmony_ci return clock; 90762306a36Sopenharmony_ci case SSB_CHIPCO_CLK_MC_M1: 90862306a36Sopenharmony_ci return (clock / m1); 90962306a36Sopenharmony_ci case SSB_CHIPCO_CLK_MC_M1M2: 91062306a36Sopenharmony_ci return (clock / (m1 * m2)); 91162306a36Sopenharmony_ci case SSB_CHIPCO_CLK_MC_M1M2M3: 91262306a36Sopenharmony_ci return (clock / (m1 * m2 * m3)); 91362306a36Sopenharmony_ci case SSB_CHIPCO_CLK_MC_M1M3: 91462306a36Sopenharmony_ci return (clock / (m1 * m3)); 91562306a36Sopenharmony_ci } 91662306a36Sopenharmony_ci return 0; 91762306a36Sopenharmony_ci case SSB_PLLTYPE_2: 91862306a36Sopenharmony_ci m1 += SSB_CHIPCO_CLK_T2_BIAS; 91962306a36Sopenharmony_ci m2 += SSB_CHIPCO_CLK_T2M2_BIAS; 92062306a36Sopenharmony_ci m3 += SSB_CHIPCO_CLK_T2_BIAS; 92162306a36Sopenharmony_ci WARN_ON(!((m1 >= 2) && (m1 <= 7))); 92262306a36Sopenharmony_ci WARN_ON(!((m2 >= 3) && (m2 <= 10))); 92362306a36Sopenharmony_ci WARN_ON(!((m3 >= 2) && (m3 <= 7))); 92462306a36Sopenharmony_ci 92562306a36Sopenharmony_ci if (!(mc & SSB_CHIPCO_CLK_T2MC_M1BYP)) 92662306a36Sopenharmony_ci clock /= m1; 92762306a36Sopenharmony_ci if (!(mc & SSB_CHIPCO_CLK_T2MC_M2BYP)) 92862306a36Sopenharmony_ci clock /= m2; 92962306a36Sopenharmony_ci if (!(mc & SSB_CHIPCO_CLK_T2MC_M3BYP)) 93062306a36Sopenharmony_ci clock /= m3; 93162306a36Sopenharmony_ci return clock; 93262306a36Sopenharmony_ci default: 93362306a36Sopenharmony_ci WARN_ON(1); 93462306a36Sopenharmony_ci } 93562306a36Sopenharmony_ci return 0; 93662306a36Sopenharmony_ci} 93762306a36Sopenharmony_ci 93862306a36Sopenharmony_ci/* Get the current speed the backplane is running at */ 93962306a36Sopenharmony_ciu32 ssb_clockspeed(struct ssb_bus *bus) 94062306a36Sopenharmony_ci{ 94162306a36Sopenharmony_ci u32 rate; 94262306a36Sopenharmony_ci u32 plltype; 94362306a36Sopenharmony_ci u32 clkctl_n, clkctl_m; 94462306a36Sopenharmony_ci 94562306a36Sopenharmony_ci if (bus->chipco.capabilities & SSB_CHIPCO_CAP_PMU) 94662306a36Sopenharmony_ci return ssb_pmu_get_controlclock(&bus->chipco); 94762306a36Sopenharmony_ci 94862306a36Sopenharmony_ci if (ssb_extif_available(&bus->extif)) 94962306a36Sopenharmony_ci ssb_extif_get_clockcontrol(&bus->extif, &plltype, 95062306a36Sopenharmony_ci &clkctl_n, &clkctl_m); 95162306a36Sopenharmony_ci else if (bus->chipco.dev) 95262306a36Sopenharmony_ci ssb_chipco_get_clockcontrol(&bus->chipco, &plltype, 95362306a36Sopenharmony_ci &clkctl_n, &clkctl_m); 95462306a36Sopenharmony_ci else 95562306a36Sopenharmony_ci return 0; 95662306a36Sopenharmony_ci 95762306a36Sopenharmony_ci if (bus->chip_id == 0x5365) { 95862306a36Sopenharmony_ci rate = 100000000; 95962306a36Sopenharmony_ci } else { 96062306a36Sopenharmony_ci rate = ssb_calc_clock_rate(plltype, clkctl_n, clkctl_m); 96162306a36Sopenharmony_ci if (plltype == SSB_PLLTYPE_3) /* 25Mhz, 2 dividers */ 96262306a36Sopenharmony_ci rate /= 2; 96362306a36Sopenharmony_ci } 96462306a36Sopenharmony_ci 96562306a36Sopenharmony_ci return rate; 96662306a36Sopenharmony_ci} 96762306a36Sopenharmony_ciEXPORT_SYMBOL(ssb_clockspeed); 96862306a36Sopenharmony_ci 96962306a36Sopenharmony_cistatic u32 ssb_tmslow_reject_bitmask(struct ssb_device *dev) 97062306a36Sopenharmony_ci{ 97162306a36Sopenharmony_ci u32 rev = ssb_read32(dev, SSB_IDLOW) & SSB_IDLOW_SSBREV; 97262306a36Sopenharmony_ci 97362306a36Sopenharmony_ci /* The REJECT bit seems to be different for Backplane rev 2.3 */ 97462306a36Sopenharmony_ci switch (rev) { 97562306a36Sopenharmony_ci case SSB_IDLOW_SSBREV_22: 97662306a36Sopenharmony_ci case SSB_IDLOW_SSBREV_24: 97762306a36Sopenharmony_ci case SSB_IDLOW_SSBREV_26: 97862306a36Sopenharmony_ci return SSB_TMSLOW_REJECT; 97962306a36Sopenharmony_ci case SSB_IDLOW_SSBREV_23: 98062306a36Sopenharmony_ci return SSB_TMSLOW_REJECT_23; 98162306a36Sopenharmony_ci case SSB_IDLOW_SSBREV_25: /* TODO - find the proper REJECT bit */ 98262306a36Sopenharmony_ci case SSB_IDLOW_SSBREV_27: /* same here */ 98362306a36Sopenharmony_ci return SSB_TMSLOW_REJECT; /* this is a guess */ 98462306a36Sopenharmony_ci case SSB_IDLOW_SSBREV: 98562306a36Sopenharmony_ci break; 98662306a36Sopenharmony_ci default: 98762306a36Sopenharmony_ci WARN(1, KERN_INFO "ssb: Backplane Revision 0x%.8X\n", rev); 98862306a36Sopenharmony_ci } 98962306a36Sopenharmony_ci return (SSB_TMSLOW_REJECT | SSB_TMSLOW_REJECT_23); 99062306a36Sopenharmony_ci} 99162306a36Sopenharmony_ci 99262306a36Sopenharmony_ciint ssb_device_is_enabled(struct ssb_device *dev) 99362306a36Sopenharmony_ci{ 99462306a36Sopenharmony_ci u32 val; 99562306a36Sopenharmony_ci u32 reject; 99662306a36Sopenharmony_ci 99762306a36Sopenharmony_ci reject = ssb_tmslow_reject_bitmask(dev); 99862306a36Sopenharmony_ci val = ssb_read32(dev, SSB_TMSLOW); 99962306a36Sopenharmony_ci val &= SSB_TMSLOW_CLOCK | SSB_TMSLOW_RESET | reject; 100062306a36Sopenharmony_ci 100162306a36Sopenharmony_ci return (val == SSB_TMSLOW_CLOCK); 100262306a36Sopenharmony_ci} 100362306a36Sopenharmony_ciEXPORT_SYMBOL(ssb_device_is_enabled); 100462306a36Sopenharmony_ci 100562306a36Sopenharmony_cistatic void ssb_flush_tmslow(struct ssb_device *dev) 100662306a36Sopenharmony_ci{ 100762306a36Sopenharmony_ci /* Make _really_ sure the device has finished the TMSLOW 100862306a36Sopenharmony_ci * register write transaction, as we risk running into 100962306a36Sopenharmony_ci * a machine check exception otherwise. 101062306a36Sopenharmony_ci * Do this by reading the register back to commit the 101162306a36Sopenharmony_ci * PCI write and delay an additional usec for the device 101262306a36Sopenharmony_ci * to react to the change. 101362306a36Sopenharmony_ci */ 101462306a36Sopenharmony_ci ssb_read32(dev, SSB_TMSLOW); 101562306a36Sopenharmony_ci udelay(1); 101662306a36Sopenharmony_ci} 101762306a36Sopenharmony_ci 101862306a36Sopenharmony_civoid ssb_device_enable(struct ssb_device *dev, u32 core_specific_flags) 101962306a36Sopenharmony_ci{ 102062306a36Sopenharmony_ci u32 val; 102162306a36Sopenharmony_ci 102262306a36Sopenharmony_ci ssb_device_disable(dev, core_specific_flags); 102362306a36Sopenharmony_ci ssb_write32(dev, SSB_TMSLOW, 102462306a36Sopenharmony_ci SSB_TMSLOW_RESET | SSB_TMSLOW_CLOCK | 102562306a36Sopenharmony_ci SSB_TMSLOW_FGC | core_specific_flags); 102662306a36Sopenharmony_ci ssb_flush_tmslow(dev); 102762306a36Sopenharmony_ci 102862306a36Sopenharmony_ci /* Clear SERR if set. This is a hw bug workaround. */ 102962306a36Sopenharmony_ci if (ssb_read32(dev, SSB_TMSHIGH) & SSB_TMSHIGH_SERR) 103062306a36Sopenharmony_ci ssb_write32(dev, SSB_TMSHIGH, 0); 103162306a36Sopenharmony_ci 103262306a36Sopenharmony_ci val = ssb_read32(dev, SSB_IMSTATE); 103362306a36Sopenharmony_ci if (val & (SSB_IMSTATE_IBE | SSB_IMSTATE_TO)) { 103462306a36Sopenharmony_ci val &= ~(SSB_IMSTATE_IBE | SSB_IMSTATE_TO); 103562306a36Sopenharmony_ci ssb_write32(dev, SSB_IMSTATE, val); 103662306a36Sopenharmony_ci } 103762306a36Sopenharmony_ci 103862306a36Sopenharmony_ci ssb_write32(dev, SSB_TMSLOW, 103962306a36Sopenharmony_ci SSB_TMSLOW_CLOCK | SSB_TMSLOW_FGC | 104062306a36Sopenharmony_ci core_specific_flags); 104162306a36Sopenharmony_ci ssb_flush_tmslow(dev); 104262306a36Sopenharmony_ci 104362306a36Sopenharmony_ci ssb_write32(dev, SSB_TMSLOW, SSB_TMSLOW_CLOCK | 104462306a36Sopenharmony_ci core_specific_flags); 104562306a36Sopenharmony_ci ssb_flush_tmslow(dev); 104662306a36Sopenharmony_ci} 104762306a36Sopenharmony_ciEXPORT_SYMBOL(ssb_device_enable); 104862306a36Sopenharmony_ci 104962306a36Sopenharmony_ci/* Wait for bitmask in a register to get set or cleared. 105062306a36Sopenharmony_ci * timeout is in units of ten-microseconds 105162306a36Sopenharmony_ci */ 105262306a36Sopenharmony_cistatic int ssb_wait_bits(struct ssb_device *dev, u16 reg, u32 bitmask, 105362306a36Sopenharmony_ci int timeout, int set) 105462306a36Sopenharmony_ci{ 105562306a36Sopenharmony_ci int i; 105662306a36Sopenharmony_ci u32 val; 105762306a36Sopenharmony_ci 105862306a36Sopenharmony_ci for (i = 0; i < timeout; i++) { 105962306a36Sopenharmony_ci val = ssb_read32(dev, reg); 106062306a36Sopenharmony_ci if (set) { 106162306a36Sopenharmony_ci if ((val & bitmask) == bitmask) 106262306a36Sopenharmony_ci return 0; 106362306a36Sopenharmony_ci } else { 106462306a36Sopenharmony_ci if (!(val & bitmask)) 106562306a36Sopenharmony_ci return 0; 106662306a36Sopenharmony_ci } 106762306a36Sopenharmony_ci udelay(10); 106862306a36Sopenharmony_ci } 106962306a36Sopenharmony_ci dev_err(dev->dev, 107062306a36Sopenharmony_ci "Timeout waiting for bitmask %08X on register %04X to %s\n", 107162306a36Sopenharmony_ci bitmask, reg, set ? "set" : "clear"); 107262306a36Sopenharmony_ci 107362306a36Sopenharmony_ci return -ETIMEDOUT; 107462306a36Sopenharmony_ci} 107562306a36Sopenharmony_ci 107662306a36Sopenharmony_civoid ssb_device_disable(struct ssb_device *dev, u32 core_specific_flags) 107762306a36Sopenharmony_ci{ 107862306a36Sopenharmony_ci u32 reject, val; 107962306a36Sopenharmony_ci 108062306a36Sopenharmony_ci if (ssb_read32(dev, SSB_TMSLOW) & SSB_TMSLOW_RESET) 108162306a36Sopenharmony_ci return; 108262306a36Sopenharmony_ci 108362306a36Sopenharmony_ci reject = ssb_tmslow_reject_bitmask(dev); 108462306a36Sopenharmony_ci 108562306a36Sopenharmony_ci if (ssb_read32(dev, SSB_TMSLOW) & SSB_TMSLOW_CLOCK) { 108662306a36Sopenharmony_ci ssb_write32(dev, SSB_TMSLOW, reject | SSB_TMSLOW_CLOCK); 108762306a36Sopenharmony_ci ssb_wait_bits(dev, SSB_TMSLOW, reject, 1000, 1); 108862306a36Sopenharmony_ci ssb_wait_bits(dev, SSB_TMSHIGH, SSB_TMSHIGH_BUSY, 1000, 0); 108962306a36Sopenharmony_ci 109062306a36Sopenharmony_ci if (ssb_read32(dev, SSB_IDLOW) & SSB_IDLOW_INITIATOR) { 109162306a36Sopenharmony_ci val = ssb_read32(dev, SSB_IMSTATE); 109262306a36Sopenharmony_ci val |= SSB_IMSTATE_REJECT; 109362306a36Sopenharmony_ci ssb_write32(dev, SSB_IMSTATE, val); 109462306a36Sopenharmony_ci ssb_wait_bits(dev, SSB_IMSTATE, SSB_IMSTATE_BUSY, 1000, 109562306a36Sopenharmony_ci 0); 109662306a36Sopenharmony_ci } 109762306a36Sopenharmony_ci 109862306a36Sopenharmony_ci ssb_write32(dev, SSB_TMSLOW, 109962306a36Sopenharmony_ci SSB_TMSLOW_FGC | SSB_TMSLOW_CLOCK | 110062306a36Sopenharmony_ci reject | SSB_TMSLOW_RESET | 110162306a36Sopenharmony_ci core_specific_flags); 110262306a36Sopenharmony_ci ssb_flush_tmslow(dev); 110362306a36Sopenharmony_ci 110462306a36Sopenharmony_ci if (ssb_read32(dev, SSB_IDLOW) & SSB_IDLOW_INITIATOR) { 110562306a36Sopenharmony_ci val = ssb_read32(dev, SSB_IMSTATE); 110662306a36Sopenharmony_ci val &= ~SSB_IMSTATE_REJECT; 110762306a36Sopenharmony_ci ssb_write32(dev, SSB_IMSTATE, val); 110862306a36Sopenharmony_ci } 110962306a36Sopenharmony_ci } 111062306a36Sopenharmony_ci 111162306a36Sopenharmony_ci ssb_write32(dev, SSB_TMSLOW, 111262306a36Sopenharmony_ci reject | SSB_TMSLOW_RESET | 111362306a36Sopenharmony_ci core_specific_flags); 111462306a36Sopenharmony_ci ssb_flush_tmslow(dev); 111562306a36Sopenharmony_ci} 111662306a36Sopenharmony_ciEXPORT_SYMBOL(ssb_device_disable); 111762306a36Sopenharmony_ci 111862306a36Sopenharmony_ci/* Some chipsets need routing known for PCIe and 64-bit DMA */ 111962306a36Sopenharmony_cistatic bool ssb_dma_translation_special_bit(struct ssb_device *dev) 112062306a36Sopenharmony_ci{ 112162306a36Sopenharmony_ci u16 chip_id = dev->bus->chip_id; 112262306a36Sopenharmony_ci 112362306a36Sopenharmony_ci if (dev->id.coreid == SSB_DEV_80211) { 112462306a36Sopenharmony_ci return (chip_id == 0x4322 || chip_id == 43221 || 112562306a36Sopenharmony_ci chip_id == 43231 || chip_id == 43222); 112662306a36Sopenharmony_ci } 112762306a36Sopenharmony_ci 112862306a36Sopenharmony_ci return false; 112962306a36Sopenharmony_ci} 113062306a36Sopenharmony_ci 113162306a36Sopenharmony_ciu32 ssb_dma_translation(struct ssb_device *dev) 113262306a36Sopenharmony_ci{ 113362306a36Sopenharmony_ci switch (dev->bus->bustype) { 113462306a36Sopenharmony_ci case SSB_BUSTYPE_SSB: 113562306a36Sopenharmony_ci return 0; 113662306a36Sopenharmony_ci case SSB_BUSTYPE_PCI: 113762306a36Sopenharmony_ci if (pci_is_pcie(dev->bus->host_pci) && 113862306a36Sopenharmony_ci ssb_read32(dev, SSB_TMSHIGH) & SSB_TMSHIGH_DMA64) { 113962306a36Sopenharmony_ci return SSB_PCIE_DMA_H32; 114062306a36Sopenharmony_ci } else { 114162306a36Sopenharmony_ci if (ssb_dma_translation_special_bit(dev)) 114262306a36Sopenharmony_ci return SSB_PCIE_DMA_H32; 114362306a36Sopenharmony_ci else 114462306a36Sopenharmony_ci return SSB_PCI_DMA; 114562306a36Sopenharmony_ci } 114662306a36Sopenharmony_ci default: 114762306a36Sopenharmony_ci __ssb_dma_not_implemented(dev); 114862306a36Sopenharmony_ci } 114962306a36Sopenharmony_ci return 0; 115062306a36Sopenharmony_ci} 115162306a36Sopenharmony_ciEXPORT_SYMBOL(ssb_dma_translation); 115262306a36Sopenharmony_ci 115362306a36Sopenharmony_ciint ssb_bus_may_powerdown(struct ssb_bus *bus) 115462306a36Sopenharmony_ci{ 115562306a36Sopenharmony_ci struct ssb_chipcommon *cc; 115662306a36Sopenharmony_ci int err = 0; 115762306a36Sopenharmony_ci 115862306a36Sopenharmony_ci /* On buses where more than one core may be working 115962306a36Sopenharmony_ci * at a time, we must not powerdown stuff if there are 116062306a36Sopenharmony_ci * still cores that may want to run. 116162306a36Sopenharmony_ci */ 116262306a36Sopenharmony_ci if (bus->bustype == SSB_BUSTYPE_SSB) 116362306a36Sopenharmony_ci goto out; 116462306a36Sopenharmony_ci 116562306a36Sopenharmony_ci cc = &bus->chipco; 116662306a36Sopenharmony_ci 116762306a36Sopenharmony_ci if (!cc->dev) 116862306a36Sopenharmony_ci goto out; 116962306a36Sopenharmony_ci if (cc->dev->id.revision < 5) 117062306a36Sopenharmony_ci goto out; 117162306a36Sopenharmony_ci 117262306a36Sopenharmony_ci ssb_chipco_set_clockmode(cc, SSB_CLKMODE_SLOW); 117362306a36Sopenharmony_ci err = ssb_pci_xtal(bus, SSB_GPIO_XTAL | SSB_GPIO_PLL, 0); 117462306a36Sopenharmony_ci if (err) 117562306a36Sopenharmony_ci goto error; 117662306a36Sopenharmony_ciout: 117762306a36Sopenharmony_ci bus->powered_up = 0; 117862306a36Sopenharmony_ci return err; 117962306a36Sopenharmony_cierror: 118062306a36Sopenharmony_ci pr_err("Bus powerdown failed\n"); 118162306a36Sopenharmony_ci goto out; 118262306a36Sopenharmony_ci} 118362306a36Sopenharmony_ciEXPORT_SYMBOL(ssb_bus_may_powerdown); 118462306a36Sopenharmony_ci 118562306a36Sopenharmony_ciint ssb_bus_powerup(struct ssb_bus *bus, bool dynamic_pctl) 118662306a36Sopenharmony_ci{ 118762306a36Sopenharmony_ci int err; 118862306a36Sopenharmony_ci enum ssb_clkmode mode; 118962306a36Sopenharmony_ci 119062306a36Sopenharmony_ci err = ssb_pci_xtal(bus, SSB_GPIO_XTAL | SSB_GPIO_PLL, 1); 119162306a36Sopenharmony_ci if (err) 119262306a36Sopenharmony_ci goto error; 119362306a36Sopenharmony_ci 119462306a36Sopenharmony_ci bus->powered_up = 1; 119562306a36Sopenharmony_ci 119662306a36Sopenharmony_ci mode = dynamic_pctl ? SSB_CLKMODE_DYNAMIC : SSB_CLKMODE_FAST; 119762306a36Sopenharmony_ci ssb_chipco_set_clockmode(&bus->chipco, mode); 119862306a36Sopenharmony_ci 119962306a36Sopenharmony_ci return 0; 120062306a36Sopenharmony_cierror: 120162306a36Sopenharmony_ci pr_err("Bus powerup failed\n"); 120262306a36Sopenharmony_ci return err; 120362306a36Sopenharmony_ci} 120462306a36Sopenharmony_ciEXPORT_SYMBOL(ssb_bus_powerup); 120562306a36Sopenharmony_ci 120662306a36Sopenharmony_cistatic void ssb_broadcast_value(struct ssb_device *dev, 120762306a36Sopenharmony_ci u32 address, u32 data) 120862306a36Sopenharmony_ci{ 120962306a36Sopenharmony_ci#ifdef CONFIG_SSB_DRIVER_PCICORE 121062306a36Sopenharmony_ci /* This is used for both, PCI and ChipCommon core, so be careful. */ 121162306a36Sopenharmony_ci BUILD_BUG_ON(SSB_PCICORE_BCAST_ADDR != SSB_CHIPCO_BCAST_ADDR); 121262306a36Sopenharmony_ci BUILD_BUG_ON(SSB_PCICORE_BCAST_DATA != SSB_CHIPCO_BCAST_DATA); 121362306a36Sopenharmony_ci#endif 121462306a36Sopenharmony_ci 121562306a36Sopenharmony_ci ssb_write32(dev, SSB_CHIPCO_BCAST_ADDR, address); 121662306a36Sopenharmony_ci ssb_read32(dev, SSB_CHIPCO_BCAST_ADDR); /* flush */ 121762306a36Sopenharmony_ci ssb_write32(dev, SSB_CHIPCO_BCAST_DATA, data); 121862306a36Sopenharmony_ci ssb_read32(dev, SSB_CHIPCO_BCAST_DATA); /* flush */ 121962306a36Sopenharmony_ci} 122062306a36Sopenharmony_ci 122162306a36Sopenharmony_civoid ssb_commit_settings(struct ssb_bus *bus) 122262306a36Sopenharmony_ci{ 122362306a36Sopenharmony_ci struct ssb_device *dev; 122462306a36Sopenharmony_ci 122562306a36Sopenharmony_ci#ifdef CONFIG_SSB_DRIVER_PCICORE 122662306a36Sopenharmony_ci dev = bus->chipco.dev ? bus->chipco.dev : bus->pcicore.dev; 122762306a36Sopenharmony_ci#else 122862306a36Sopenharmony_ci dev = bus->chipco.dev; 122962306a36Sopenharmony_ci#endif 123062306a36Sopenharmony_ci if (WARN_ON(!dev)) 123162306a36Sopenharmony_ci return; 123262306a36Sopenharmony_ci /* This forces an update of the cached registers. */ 123362306a36Sopenharmony_ci ssb_broadcast_value(dev, 0xFD8, 0); 123462306a36Sopenharmony_ci} 123562306a36Sopenharmony_ciEXPORT_SYMBOL(ssb_commit_settings); 123662306a36Sopenharmony_ci 123762306a36Sopenharmony_ciu32 ssb_admatch_base(u32 adm) 123862306a36Sopenharmony_ci{ 123962306a36Sopenharmony_ci u32 base = 0; 124062306a36Sopenharmony_ci 124162306a36Sopenharmony_ci switch (adm & SSB_ADM_TYPE) { 124262306a36Sopenharmony_ci case SSB_ADM_TYPE0: 124362306a36Sopenharmony_ci base = (adm & SSB_ADM_BASE0); 124462306a36Sopenharmony_ci break; 124562306a36Sopenharmony_ci case SSB_ADM_TYPE1: 124662306a36Sopenharmony_ci WARN_ON(adm & SSB_ADM_NEG); /* unsupported */ 124762306a36Sopenharmony_ci base = (adm & SSB_ADM_BASE1); 124862306a36Sopenharmony_ci break; 124962306a36Sopenharmony_ci case SSB_ADM_TYPE2: 125062306a36Sopenharmony_ci WARN_ON(adm & SSB_ADM_NEG); /* unsupported */ 125162306a36Sopenharmony_ci base = (adm & SSB_ADM_BASE2); 125262306a36Sopenharmony_ci break; 125362306a36Sopenharmony_ci default: 125462306a36Sopenharmony_ci WARN_ON(1); 125562306a36Sopenharmony_ci } 125662306a36Sopenharmony_ci 125762306a36Sopenharmony_ci return base; 125862306a36Sopenharmony_ci} 125962306a36Sopenharmony_ciEXPORT_SYMBOL(ssb_admatch_base); 126062306a36Sopenharmony_ci 126162306a36Sopenharmony_ciu32 ssb_admatch_size(u32 adm) 126262306a36Sopenharmony_ci{ 126362306a36Sopenharmony_ci u32 size = 0; 126462306a36Sopenharmony_ci 126562306a36Sopenharmony_ci switch (adm & SSB_ADM_TYPE) { 126662306a36Sopenharmony_ci case SSB_ADM_TYPE0: 126762306a36Sopenharmony_ci size = ((adm & SSB_ADM_SZ0) >> SSB_ADM_SZ0_SHIFT); 126862306a36Sopenharmony_ci break; 126962306a36Sopenharmony_ci case SSB_ADM_TYPE1: 127062306a36Sopenharmony_ci WARN_ON(adm & SSB_ADM_NEG); /* unsupported */ 127162306a36Sopenharmony_ci size = ((adm & SSB_ADM_SZ1) >> SSB_ADM_SZ1_SHIFT); 127262306a36Sopenharmony_ci break; 127362306a36Sopenharmony_ci case SSB_ADM_TYPE2: 127462306a36Sopenharmony_ci WARN_ON(adm & SSB_ADM_NEG); /* unsupported */ 127562306a36Sopenharmony_ci size = ((adm & SSB_ADM_SZ2) >> SSB_ADM_SZ2_SHIFT); 127662306a36Sopenharmony_ci break; 127762306a36Sopenharmony_ci default: 127862306a36Sopenharmony_ci WARN_ON(1); 127962306a36Sopenharmony_ci } 128062306a36Sopenharmony_ci size = (1 << (size + 1)); 128162306a36Sopenharmony_ci 128262306a36Sopenharmony_ci return size; 128362306a36Sopenharmony_ci} 128462306a36Sopenharmony_ciEXPORT_SYMBOL(ssb_admatch_size); 128562306a36Sopenharmony_ci 128662306a36Sopenharmony_cistatic int __init ssb_modinit(void) 128762306a36Sopenharmony_ci{ 128862306a36Sopenharmony_ci int err; 128962306a36Sopenharmony_ci 129062306a36Sopenharmony_ci /* See the comment at the ssb_is_early_boot definition */ 129162306a36Sopenharmony_ci ssb_is_early_boot = 0; 129262306a36Sopenharmony_ci err = bus_register(&ssb_bustype); 129362306a36Sopenharmony_ci if (err) 129462306a36Sopenharmony_ci return err; 129562306a36Sopenharmony_ci 129662306a36Sopenharmony_ci /* Maybe we already registered some buses at early boot. 129762306a36Sopenharmony_ci * Check for this and attach them 129862306a36Sopenharmony_ci */ 129962306a36Sopenharmony_ci ssb_buses_lock(); 130062306a36Sopenharmony_ci err = ssb_attach_queued_buses(); 130162306a36Sopenharmony_ci ssb_buses_unlock(); 130262306a36Sopenharmony_ci if (err) { 130362306a36Sopenharmony_ci bus_unregister(&ssb_bustype); 130462306a36Sopenharmony_ci goto out; 130562306a36Sopenharmony_ci } 130662306a36Sopenharmony_ci 130762306a36Sopenharmony_ci err = b43_pci_ssb_bridge_init(); 130862306a36Sopenharmony_ci if (err) { 130962306a36Sopenharmony_ci pr_err("Broadcom 43xx PCI-SSB-bridge initialization failed\n"); 131062306a36Sopenharmony_ci /* don't fail SSB init because of this */ 131162306a36Sopenharmony_ci } 131262306a36Sopenharmony_ci err = ssb_host_pcmcia_init(); 131362306a36Sopenharmony_ci if (err) { 131462306a36Sopenharmony_ci pr_err("PCMCIA host initialization failed\n"); 131562306a36Sopenharmony_ci /* don't fail SSB init because of this */ 131662306a36Sopenharmony_ci } 131762306a36Sopenharmony_ci err = ssb_gige_init(); 131862306a36Sopenharmony_ci if (err) { 131962306a36Sopenharmony_ci pr_err("SSB Broadcom Gigabit Ethernet driver initialization failed\n"); 132062306a36Sopenharmony_ci /* don't fail SSB init because of this */ 132162306a36Sopenharmony_ci err = 0; 132262306a36Sopenharmony_ci } 132362306a36Sopenharmony_ciout: 132462306a36Sopenharmony_ci return err; 132562306a36Sopenharmony_ci} 132662306a36Sopenharmony_ci/* ssb must be initialized after PCI but before the ssb drivers. 132762306a36Sopenharmony_ci * That means we must use some initcall between subsys_initcall 132862306a36Sopenharmony_ci * and device_initcall. 132962306a36Sopenharmony_ci */ 133062306a36Sopenharmony_cifs_initcall(ssb_modinit); 133162306a36Sopenharmony_ci 133262306a36Sopenharmony_cistatic void __exit ssb_modexit(void) 133362306a36Sopenharmony_ci{ 133462306a36Sopenharmony_ci ssb_gige_exit(); 133562306a36Sopenharmony_ci ssb_host_pcmcia_exit(); 133662306a36Sopenharmony_ci b43_pci_ssb_bridge_exit(); 133762306a36Sopenharmony_ci bus_unregister(&ssb_bustype); 133862306a36Sopenharmony_ci} 133962306a36Sopenharmony_cimodule_exit(ssb_modexit) 1340