11c0c13ebSAurelien Jarno /* 21c0c13ebSAurelien Jarno * Copyright (C) 2004 Florian Schirmer <jolt@tuxbox.org> 31c0c13ebSAurelien Jarno * Copyright (C) 2006 Felix Fietkau <nbd@openwrt.org> 41c0c13ebSAurelien Jarno * Copyright (C) 2006 Michael Buesch <mb@bu3sch.de> 5*121915c4SWaldemar Brodkorb * Copyright (C) 2010 Waldemar Brodkorb <wbx@openadk.org> 61c0c13ebSAurelien Jarno * 71c0c13ebSAurelien Jarno * This program is free software; you can redistribute it and/or modify it 81c0c13ebSAurelien Jarno * under the terms of the GNU General Public License as published by the 91c0c13ebSAurelien Jarno * Free Software Foundation; either version 2 of the License, or (at your 101c0c13ebSAurelien Jarno * option) any later version. 111c0c13ebSAurelien Jarno * 121c0c13ebSAurelien Jarno * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED 131c0c13ebSAurelien Jarno * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF 141c0c13ebSAurelien Jarno * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN 151c0c13ebSAurelien Jarno * NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, 161c0c13ebSAurelien Jarno * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT 171c0c13ebSAurelien Jarno * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF 181c0c13ebSAurelien Jarno * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON 191c0c13ebSAurelien Jarno * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 201c0c13ebSAurelien Jarno * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF 211c0c13ebSAurelien Jarno * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 221c0c13ebSAurelien Jarno * 231c0c13ebSAurelien Jarno * You should have received a copy of the GNU General Public License along 241c0c13ebSAurelien Jarno * with this program; if not, write to the Free Software Foundation, Inc., 251c0c13ebSAurelien Jarno * 675 Mass Ave, Cambridge, MA 02139, USA. 261c0c13ebSAurelien Jarno */ 271c0c13ebSAurelien Jarno 281c0c13ebSAurelien Jarno #include <linux/types.h> 291c0c13ebSAurelien Jarno #include <linux/ssb/ssb.h> 30b06f3e19SAurelien Jarno #include <linux/ssb/ssb_embedded.h> 3125e5fb97SAurelien Jarno #include <asm/bootinfo.h> 321c0c13ebSAurelien Jarno #include <asm/reboot.h> 331c0c13ebSAurelien Jarno #include <asm/time.h> 341c0c13ebSAurelien Jarno #include <bcm47xx.h> 3525e5fb97SAurelien Jarno #include <asm/fw/cfe/cfe_api.h> 36*121915c4SWaldemar Brodkorb #include <asm/mach-bcm47xx/nvram.h> 371c0c13ebSAurelien Jarno 381c0c13ebSAurelien Jarno struct ssb_bus ssb_bcm47xx; 391c0c13ebSAurelien Jarno EXPORT_SYMBOL(ssb_bcm47xx); 401c0c13ebSAurelien Jarno 411c0c13ebSAurelien Jarno static void bcm47xx_machine_restart(char *command) 421c0c13ebSAurelien Jarno { 431c0c13ebSAurelien Jarno printk(KERN_ALERT "Please stand by while rebooting the system...\n"); 441c0c13ebSAurelien Jarno local_irq_disable(); 451c0c13ebSAurelien Jarno /* Set the watchdog timer to reset immediately */ 46b06f3e19SAurelien Jarno ssb_watchdog_timer_set(&ssb_bcm47xx, 1); 471c0c13ebSAurelien Jarno while (1) 481c0c13ebSAurelien Jarno cpu_relax(); 491c0c13ebSAurelien Jarno } 501c0c13ebSAurelien Jarno 511c0c13ebSAurelien Jarno static void bcm47xx_machine_halt(void) 521c0c13ebSAurelien Jarno { 531c0c13ebSAurelien Jarno /* Disable interrupts and watchdog and spin forever */ 541c0c13ebSAurelien Jarno local_irq_disable(); 55b06f3e19SAurelien Jarno ssb_watchdog_timer_set(&ssb_bcm47xx, 0); 561c0c13ebSAurelien Jarno while (1) 571c0c13ebSAurelien Jarno cpu_relax(); 581c0c13ebSAurelien Jarno } 591c0c13ebSAurelien Jarno 6025e5fb97SAurelien Jarno static void str2eaddr(char *str, char *dest) 6125e5fb97SAurelien Jarno { 6225e5fb97SAurelien Jarno int i = 0; 6325e5fb97SAurelien Jarno 6425e5fb97SAurelien Jarno if (str == NULL) { 6525e5fb97SAurelien Jarno memset(dest, 0, 6); 6625e5fb97SAurelien Jarno return; 6725e5fb97SAurelien Jarno } 6825e5fb97SAurelien Jarno 6925e5fb97SAurelien Jarno for (;;) { 7025e5fb97SAurelien Jarno dest[i++] = (char) simple_strtoul(str, NULL, 16); 7125e5fb97SAurelien Jarno str += 2; 7225e5fb97SAurelien Jarno if (!*str++ || i == 6) 7325e5fb97SAurelien Jarno break; 7425e5fb97SAurelien Jarno } 7525e5fb97SAurelien Jarno } 7625e5fb97SAurelien Jarno 771c0c13ebSAurelien Jarno static int bcm47xx_get_invariants(struct ssb_bus *bus, 781c0c13ebSAurelien Jarno struct ssb_init_invariants *iv) 791c0c13ebSAurelien Jarno { 8025e5fb97SAurelien Jarno char buf[100]; 8125e5fb97SAurelien Jarno 8225e5fb97SAurelien Jarno /* Fill boardinfo structure */ 8325e5fb97SAurelien Jarno memset(&(iv->boardinfo), 0 , sizeof(struct ssb_boardinfo)); 8425e5fb97SAurelien Jarno 85*121915c4SWaldemar Brodkorb if (cfe_getenv("boardvendor", buf, sizeof(buf)) >= 0 || 86*121915c4SWaldemar Brodkorb nvram_getenv("boardvendor", buf, sizeof(buf)) >= 0) 8725e5fb97SAurelien Jarno iv->boardinfo.type = (u16)simple_strtoul(buf, NULL, 0); 88*121915c4SWaldemar Brodkorb if (cfe_getenv("boardtype", buf, sizeof(buf)) >= 0 || 89*121915c4SWaldemar Brodkorb nvram_getenv("boardtype", buf, sizeof(buf)) >= 0) 9025e5fb97SAurelien Jarno iv->boardinfo.type = (u16)simple_strtoul(buf, NULL, 0); 91*121915c4SWaldemar Brodkorb if (cfe_getenv("boardrev", buf, sizeof(buf)) >= 0 || 92*121915c4SWaldemar Brodkorb nvram_getenv("boardrev", buf, sizeof(buf)) >= 0) 9325e5fb97SAurelien Jarno iv->boardinfo.rev = (u16)simple_strtoul(buf, NULL, 0); 9425e5fb97SAurelien Jarno 9525e5fb97SAurelien Jarno /* Fill sprom structure */ 9625e5fb97SAurelien Jarno memset(&(iv->sprom), 0, sizeof(struct ssb_sprom)); 9725e5fb97SAurelien Jarno iv->sprom.revision = 3; 9825e5fb97SAurelien Jarno 99*121915c4SWaldemar Brodkorb if (cfe_getenv("et0macaddr", buf, sizeof(buf)) >= 0 || 100*121915c4SWaldemar Brodkorb nvram_getenv("et0macaddr", buf, sizeof(buf)) >= 0) 101cc2d6f70SAurelien Jarno str2eaddr(buf, iv->sprom.et0mac); 102*121915c4SWaldemar Brodkorb 103*121915c4SWaldemar Brodkorb if (cfe_getenv("et1macaddr", buf, sizeof(buf)) >= 0 || 104*121915c4SWaldemar Brodkorb nvram_getenv("et1macaddr", buf, sizeof(buf)) >= 0) 105cc2d6f70SAurelien Jarno str2eaddr(buf, iv->sprom.et1mac); 106*121915c4SWaldemar Brodkorb 107*121915c4SWaldemar Brodkorb if (cfe_getenv("et0phyaddr", buf, sizeof(buf)) >= 0 || 108*121915c4SWaldemar Brodkorb nvram_getenv("et0phyaddr", buf, sizeof(buf)) >= 0) 109*121915c4SWaldemar Brodkorb iv->sprom.et0phyaddr = simple_strtoul(buf, NULL, 0); 110*121915c4SWaldemar Brodkorb 111*121915c4SWaldemar Brodkorb if (cfe_getenv("et1phyaddr", buf, sizeof(buf)) >= 0 || 112*121915c4SWaldemar Brodkorb nvram_getenv("et1phyaddr", buf, sizeof(buf)) >= 0) 113*121915c4SWaldemar Brodkorb iv->sprom.et1phyaddr = simple_strtoul(buf, NULL, 0); 114*121915c4SWaldemar Brodkorb 115*121915c4SWaldemar Brodkorb if (cfe_getenv("et0mdcport", buf, sizeof(buf)) >= 0 || 116*121915c4SWaldemar Brodkorb nvram_getenv("et0mdcport", buf, sizeof(buf)) >= 0) 117cc2d6f70SAurelien Jarno iv->sprom.et0mdcport = simple_strtoul(buf, NULL, 10); 118*121915c4SWaldemar Brodkorb 119*121915c4SWaldemar Brodkorb if (cfe_getenv("et1mdcport", buf, sizeof(buf)) >= 0 || 120*121915c4SWaldemar Brodkorb nvram_getenv("et1mdcport", buf, sizeof(buf)) >= 0) 121cc2d6f70SAurelien Jarno iv->sprom.et1mdcport = simple_strtoul(buf, NULL, 10); 12225e5fb97SAurelien Jarno 1231c0c13ebSAurelien Jarno return 0; 1241c0c13ebSAurelien Jarno } 1251c0c13ebSAurelien Jarno 1261c0c13ebSAurelien Jarno void __init plat_mem_setup(void) 1271c0c13ebSAurelien Jarno { 1281c0c13ebSAurelien Jarno int err; 1291c0c13ebSAurelien Jarno 1301c0c13ebSAurelien Jarno err = ssb_bus_ssbbus_register(&ssb_bcm47xx, SSB_ENUM_BASE, 1311c0c13ebSAurelien Jarno bcm47xx_get_invariants); 1321c0c13ebSAurelien Jarno if (err) 1331c0c13ebSAurelien Jarno panic("Failed to initialize SSB bus (err %d)\n", err); 1341c0c13ebSAurelien Jarno 1351c0c13ebSAurelien Jarno _machine_restart = bcm47xx_machine_restart; 1361c0c13ebSAurelien Jarno _machine_halt = bcm47xx_machine_halt; 1371c0c13ebSAurelien Jarno pm_power_off = bcm47xx_machine_halt; 1381c0c13ebSAurelien Jarno } 139