linux/arch/mips/bcm47xx/setup.c
<<
>>
Prefs
   1/*
   2 *  Copyright (C) 2004 Florian Schirmer <jolt@tuxbox.org>
   3 *  Copyright (C) 2006 Felix Fietkau <nbd@openwrt.org>
   4 *  Copyright (C) 2006 Michael Buesch <m@bues.ch>
   5 *  Copyright (C) 2010 Waldemar Brodkorb <wbx@openadk.org>
   6 *  Copyright (C) 2010-2012 Hauke Mehrtens <hauke@hauke-m.de>
   7 *
   8 *  This program is free software; you can redistribute  it and/or modify it
   9 *  under  the terms of  the GNU General  Public License as published by the
  10 *  Free Software Foundation;  either version 2 of the  License, or (at your
  11 *  option) any later version.
  12 *
  13 *  THIS  SOFTWARE  IS PROVIDED   ``AS  IS'' AND   ANY  EXPRESS OR IMPLIED
  14 *  WARRANTIES,   INCLUDING, BUT NOT  LIMITED  TO, THE IMPLIED WARRANTIES OF
  15 *  MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.  IN
  16 *  NO  EVENT  SHALL   THE AUTHOR  BE    LIABLE FOR ANY   DIRECT, INDIRECT,
  17 *  INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
  18 *  NOT LIMITED   TO, PROCUREMENT OF  SUBSTITUTE GOODS  OR SERVICES; LOSS OF
  19 *  USE, DATA,  OR PROFITS; OR  BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
  20 *  ANY THEORY OF LIABILITY, WHETHER IN  CONTRACT, STRICT LIABILITY, OR TORT
  21 *  (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
  22 *  THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
  23 *
  24 *  You should have received a copy of the  GNU General Public License along
  25 *  with this program; if not, write  to the Free Software Foundation, Inc.,
  26 *  675 Mass Ave, Cambridge, MA 02139, USA.
  27 */
  28
  29#include <linux/export.h>
  30#include <linux/types.h>
  31#include <linux/ssb/ssb.h>
  32#include <linux/ssb/ssb_embedded.h>
  33#include <linux/bcma/bcma_soc.h>
  34#include <asm/bootinfo.h>
  35#include <asm/reboot.h>
  36#include <asm/time.h>
  37#include <bcm47xx.h>
  38#include <bcm47xx_nvram.h>
  39
  40union bcm47xx_bus bcm47xx_bus;
  41EXPORT_SYMBOL(bcm47xx_bus);
  42
  43enum bcm47xx_bus_type bcm47xx_bus_type;
  44EXPORT_SYMBOL(bcm47xx_bus_type);
  45
  46static void bcm47xx_machine_restart(char *command)
  47{
  48        printk(KERN_ALERT "Please stand by while rebooting the system...\n");
  49        local_irq_disable();
  50        /* Set the watchdog timer to reset immediately */
  51        switch (bcm47xx_bus_type) {
  52#ifdef CONFIG_BCM47XX_SSB
  53        case BCM47XX_BUS_TYPE_SSB:
  54                ssb_watchdog_timer_set(&bcm47xx_bus.ssb, 1);
  55                break;
  56#endif
  57#ifdef CONFIG_BCM47XX_BCMA
  58        case BCM47XX_BUS_TYPE_BCMA:
  59                bcma_chipco_watchdog_timer_set(&bcm47xx_bus.bcma.bus.drv_cc, 1);
  60                break;
  61#endif
  62        }
  63        while (1)
  64                cpu_relax();
  65}
  66
  67static void bcm47xx_machine_halt(void)
  68{
  69        /* Disable interrupts and watchdog and spin forever */
  70        local_irq_disable();
  71        switch (bcm47xx_bus_type) {
  72#ifdef CONFIG_BCM47XX_SSB
  73        case BCM47XX_BUS_TYPE_SSB:
  74                ssb_watchdog_timer_set(&bcm47xx_bus.ssb, 0);
  75                break;
  76#endif
  77#ifdef CONFIG_BCM47XX_BCMA
  78        case BCM47XX_BUS_TYPE_BCMA:
  79                bcma_chipco_watchdog_timer_set(&bcm47xx_bus.bcma.bus.drv_cc, 0);
  80                break;
  81#endif
  82        }
  83        while (1)
  84                cpu_relax();
  85}
  86
  87#ifdef CONFIG_BCM47XX_SSB
  88static int bcm47xx_get_sprom_ssb(struct ssb_bus *bus, struct ssb_sprom *out)
  89{
  90        char prefix[10];
  91
  92        if (bus->bustype == SSB_BUSTYPE_PCI) {
  93                memset(out, 0, sizeof(struct ssb_sprom));
  94                snprintf(prefix, sizeof(prefix), "pci/%u/%u/",
  95                         bus->host_pci->bus->number + 1,
  96                         PCI_SLOT(bus->host_pci->devfn));
  97                bcm47xx_fill_sprom(out, prefix, false);
  98                return 0;
  99        } else {
 100                printk(KERN_WARNING "bcm47xx: unable to fill SPROM for given bustype.\n");
 101                return -EINVAL;
 102        }
 103}
 104
 105static int bcm47xx_get_invariants(struct ssb_bus *bus,
 106                                  struct ssb_init_invariants *iv)
 107{
 108        char buf[20];
 109
 110        /* Fill boardinfo structure */
 111        memset(&(iv->boardinfo), 0 , sizeof(struct ssb_boardinfo));
 112
 113        bcm47xx_fill_ssb_boardinfo(&iv->boardinfo, NULL);
 114
 115        memset(&iv->sprom, 0, sizeof(struct ssb_sprom));
 116        bcm47xx_fill_sprom(&iv->sprom, NULL, false);
 117
 118        if (bcm47xx_nvram_getenv("cardbus", buf, sizeof(buf)) >= 0)
 119                iv->has_cardbus_slot = !!simple_strtoul(buf, NULL, 10);
 120
 121        return 0;
 122}
 123
 124static void __init bcm47xx_register_ssb(void)
 125{
 126        int err;
 127        char buf[100];
 128        struct ssb_mipscore *mcore;
 129
 130        err = ssb_arch_register_fallback_sprom(&bcm47xx_get_sprom_ssb);
 131        if (err)
 132                printk(KERN_WARNING "bcm47xx: someone else already registered"
 133                        " a ssb SPROM callback handler (err %d)\n", err);
 134
 135        err = ssb_bus_ssbbus_register(&(bcm47xx_bus.ssb), SSB_ENUM_BASE,
 136                                      bcm47xx_get_invariants);
 137        if (err)
 138                panic("Failed to initialize SSB bus (err %d)", err);
 139
 140        mcore = &bcm47xx_bus.ssb.mipscore;
 141        if (bcm47xx_nvram_getenv("kernel_args", buf, sizeof(buf)) >= 0) {
 142                if (strstr(buf, "console=ttyS1")) {
 143                        struct ssb_serial_port port;
 144
 145                        printk(KERN_DEBUG "Swapping serial ports!\n");
 146                        /* swap serial ports */
 147                        memcpy(&port, &mcore->serial_ports[0], sizeof(port));
 148                        memcpy(&mcore->serial_ports[0], &mcore->serial_ports[1],
 149                               sizeof(port));
 150                        memcpy(&mcore->serial_ports[1], &port, sizeof(port));
 151                }
 152        }
 153}
 154#endif
 155
 156#ifdef CONFIG_BCM47XX_BCMA
 157static int bcm47xx_get_sprom_bcma(struct bcma_bus *bus, struct ssb_sprom *out)
 158{
 159        char prefix[10];
 160        struct bcma_device *core;
 161
 162        switch (bus->hosttype) {
 163        case BCMA_HOSTTYPE_PCI:
 164                memset(out, 0, sizeof(struct ssb_sprom));
 165                snprintf(prefix, sizeof(prefix), "pci/%u/%u/",
 166                         bus->host_pci->bus->number + 1,
 167                         PCI_SLOT(bus->host_pci->devfn));
 168                bcm47xx_fill_sprom(out, prefix, false);
 169                return 0;
 170        case BCMA_HOSTTYPE_SOC:
 171                memset(out, 0, sizeof(struct ssb_sprom));
 172                core = bcma_find_core(bus, BCMA_CORE_80211);
 173                if (core) {
 174                        snprintf(prefix, sizeof(prefix), "sb/%u/",
 175                                 core->core_index);
 176                        bcm47xx_fill_sprom(out, prefix, true);
 177                } else {
 178                        bcm47xx_fill_sprom(out, NULL, false);
 179                }
 180                return 0;
 181        default:
 182                pr_warn("bcm47xx: unable to fill SPROM for given bustype.\n");
 183                return -EINVAL;
 184        }
 185}
 186
 187static void __init bcm47xx_register_bcma(void)
 188{
 189        int err;
 190
 191        err = bcma_arch_register_fallback_sprom(&bcm47xx_get_sprom_bcma);
 192        if (err)
 193                pr_warn("bcm47xx: someone else already registered a bcma SPROM callback handler (err %d)\n", err);
 194
 195        err = bcma_host_soc_register(&bcm47xx_bus.bcma);
 196        if (err)
 197                panic("Failed to initialize BCMA bus (err %d)", err);
 198
 199        bcm47xx_fill_bcma_boardinfo(&bcm47xx_bus.bcma.bus.boardinfo, NULL);
 200}
 201#endif
 202
 203void __init plat_mem_setup(void)
 204{
 205        struct cpuinfo_mips *c = &current_cpu_data;
 206
 207        if (c->cputype == CPU_74K) {
 208                printk(KERN_INFO "bcm47xx: using bcma bus\n");
 209#ifdef CONFIG_BCM47XX_BCMA
 210                bcm47xx_bus_type = BCM47XX_BUS_TYPE_BCMA;
 211                bcm47xx_register_bcma();
 212#endif
 213        } else {
 214                printk(KERN_INFO "bcm47xx: using ssb bus\n");
 215#ifdef CONFIG_BCM47XX_SSB
 216                bcm47xx_bus_type = BCM47XX_BUS_TYPE_SSB;
 217                bcm47xx_register_ssb();
 218#endif
 219        }
 220
 221        _machine_restart = bcm47xx_machine_restart;
 222        _machine_halt = bcm47xx_machine_halt;
 223        pm_power_off = bcm47xx_machine_halt;
 224}
 225
 226static int __init bcm47xx_register_bus_complete(void)
 227{
 228        switch (bcm47xx_bus_type) {
 229#ifdef CONFIG_BCM47XX_SSB
 230        case BCM47XX_BUS_TYPE_SSB:
 231                /* Nothing to do */
 232                break;
 233#endif
 234#ifdef CONFIG_BCM47XX_BCMA
 235        case BCM47XX_BUS_TYPE_BCMA:
 236                bcma_bus_register(&bcm47xx_bus.bcma.bus);
 237                break;
 238#endif
 239        }
 240        return 0;
 241}
 242device_initcall(bcm47xx_register_bus_complete);
 243