xref: /OK3568_Linux_fs/kernel/arch/mips/bcm47xx/setup.c (revision 4882a59341e53eb6f0b4789bf948001014eff981)
1*4882a593Smuzhiyun /*
2*4882a593Smuzhiyun  *  Copyright (C) 2004 Florian Schirmer <jolt@tuxbox.org>
3*4882a593Smuzhiyun  *  Copyright (C) 2006 Felix Fietkau <nbd@openwrt.org>
4*4882a593Smuzhiyun  *  Copyright (C) 2006 Michael Buesch <m@bues.ch>
5*4882a593Smuzhiyun  *  Copyright (C) 2010 Waldemar Brodkorb <wbx@openadk.org>
6*4882a593Smuzhiyun  *  Copyright (C) 2010-2012 Hauke Mehrtens <hauke@hauke-m.de>
7*4882a593Smuzhiyun  *
8*4882a593Smuzhiyun  *  This program is free software; you can redistribute  it and/or modify it
9*4882a593Smuzhiyun  *  under  the terms of  the GNU General  Public License as published by the
10*4882a593Smuzhiyun  *  Free Software Foundation;  either version 2 of the  License, or (at your
11*4882a593Smuzhiyun  *  option) any later version.
12*4882a593Smuzhiyun  *
13*4882a593Smuzhiyun  *  THIS  SOFTWARE  IS PROVIDED   ``AS  IS'' AND   ANY  EXPRESS OR IMPLIED
14*4882a593Smuzhiyun  *  WARRANTIES,   INCLUDING, BUT NOT  LIMITED  TO, THE IMPLIED WARRANTIES OF
15*4882a593Smuzhiyun  *  MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.  IN
16*4882a593Smuzhiyun  *  NO  EVENT  SHALL   THE AUTHOR  BE    LIABLE FOR ANY   DIRECT, INDIRECT,
17*4882a593Smuzhiyun  *  INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
18*4882a593Smuzhiyun  *  NOT LIMITED   TO, PROCUREMENT OF  SUBSTITUTE GOODS  OR SERVICES; LOSS OF
19*4882a593Smuzhiyun  *  USE, DATA,  OR PROFITS; OR  BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
20*4882a593Smuzhiyun  *  ANY THEORY OF LIABILITY, WHETHER IN  CONTRACT, STRICT LIABILITY, OR TORT
21*4882a593Smuzhiyun  *  (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
22*4882a593Smuzhiyun  *  THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
23*4882a593Smuzhiyun  *
24*4882a593Smuzhiyun  *  You should have received a copy of the  GNU General Public License along
25*4882a593Smuzhiyun  *  with this program; if not, write  to the Free Software Foundation, Inc.,
26*4882a593Smuzhiyun  *  675 Mass Ave, Cambridge, MA 02139, USA.
27*4882a593Smuzhiyun  */
28*4882a593Smuzhiyun 
29*4882a593Smuzhiyun #include "bcm47xx_private.h"
30*4882a593Smuzhiyun 
31*4882a593Smuzhiyun #include <linux/bcm47xx_sprom.h>
32*4882a593Smuzhiyun #include <linux/export.h>
33*4882a593Smuzhiyun #include <linux/types.h>
34*4882a593Smuzhiyun #include <linux/ethtool.h>
35*4882a593Smuzhiyun #include <linux/phy.h>
36*4882a593Smuzhiyun #include <linux/phy_fixed.h>
37*4882a593Smuzhiyun #include <linux/ssb/ssb.h>
38*4882a593Smuzhiyun #include <linux/ssb/ssb_embedded.h>
39*4882a593Smuzhiyun #include <linux/bcma/bcma_soc.h>
40*4882a593Smuzhiyun #include <asm/bootinfo.h>
41*4882a593Smuzhiyun #include <asm/idle.h>
42*4882a593Smuzhiyun #include <asm/prom.h>
43*4882a593Smuzhiyun #include <asm/reboot.h>
44*4882a593Smuzhiyun #include <asm/time.h>
45*4882a593Smuzhiyun #include <bcm47xx.h>
46*4882a593Smuzhiyun #include <bcm47xx_board.h>
47*4882a593Smuzhiyun 
48*4882a593Smuzhiyun union bcm47xx_bus bcm47xx_bus;
49*4882a593Smuzhiyun EXPORT_SYMBOL(bcm47xx_bus);
50*4882a593Smuzhiyun 
51*4882a593Smuzhiyun enum bcm47xx_bus_type bcm47xx_bus_type;
52*4882a593Smuzhiyun EXPORT_SYMBOL(bcm47xx_bus_type);
53*4882a593Smuzhiyun 
bcm47xx_machine_restart(char * command)54*4882a593Smuzhiyun static void bcm47xx_machine_restart(char *command)
55*4882a593Smuzhiyun {
56*4882a593Smuzhiyun 	pr_alert("Please stand by while rebooting the system...\n");
57*4882a593Smuzhiyun 	local_irq_disable();
58*4882a593Smuzhiyun 	/* Set the watchdog timer to reset immediately */
59*4882a593Smuzhiyun 	switch (bcm47xx_bus_type) {
60*4882a593Smuzhiyun #ifdef CONFIG_BCM47XX_SSB
61*4882a593Smuzhiyun 	case BCM47XX_BUS_TYPE_SSB:
62*4882a593Smuzhiyun 		if (bcm47xx_bus.ssb.chip_id == 0x4785)
63*4882a593Smuzhiyun 			write_c0_diag4(1 << 22);
64*4882a593Smuzhiyun 		ssb_watchdog_timer_set(&bcm47xx_bus.ssb, 1);
65*4882a593Smuzhiyun 		if (bcm47xx_bus.ssb.chip_id == 0x4785) {
66*4882a593Smuzhiyun 			__asm__ __volatile__(
67*4882a593Smuzhiyun 				".set\tmips3\n\t"
68*4882a593Smuzhiyun 				"sync\n\t"
69*4882a593Smuzhiyun 				"wait\n\t"
70*4882a593Smuzhiyun 				".set\tmips0");
71*4882a593Smuzhiyun 		}
72*4882a593Smuzhiyun 		break;
73*4882a593Smuzhiyun #endif
74*4882a593Smuzhiyun #ifdef CONFIG_BCM47XX_BCMA
75*4882a593Smuzhiyun 	case BCM47XX_BUS_TYPE_BCMA:
76*4882a593Smuzhiyun 		bcma_chipco_watchdog_timer_set(&bcm47xx_bus.bcma.bus.drv_cc, 1);
77*4882a593Smuzhiyun 		break;
78*4882a593Smuzhiyun #endif
79*4882a593Smuzhiyun 	}
80*4882a593Smuzhiyun 	while (1)
81*4882a593Smuzhiyun 		cpu_relax();
82*4882a593Smuzhiyun }
83*4882a593Smuzhiyun 
bcm47xx_machine_halt(void)84*4882a593Smuzhiyun static void bcm47xx_machine_halt(void)
85*4882a593Smuzhiyun {
86*4882a593Smuzhiyun 	/* Disable interrupts and watchdog and spin forever */
87*4882a593Smuzhiyun 	local_irq_disable();
88*4882a593Smuzhiyun 	switch (bcm47xx_bus_type) {
89*4882a593Smuzhiyun #ifdef CONFIG_BCM47XX_SSB
90*4882a593Smuzhiyun 	case BCM47XX_BUS_TYPE_SSB:
91*4882a593Smuzhiyun 		ssb_watchdog_timer_set(&bcm47xx_bus.ssb, 0);
92*4882a593Smuzhiyun 		break;
93*4882a593Smuzhiyun #endif
94*4882a593Smuzhiyun #ifdef CONFIG_BCM47XX_BCMA
95*4882a593Smuzhiyun 	case BCM47XX_BUS_TYPE_BCMA:
96*4882a593Smuzhiyun 		bcma_chipco_watchdog_timer_set(&bcm47xx_bus.bcma.bus.drv_cc, 0);
97*4882a593Smuzhiyun 		break;
98*4882a593Smuzhiyun #endif
99*4882a593Smuzhiyun 	}
100*4882a593Smuzhiyun 	while (1)
101*4882a593Smuzhiyun 		cpu_relax();
102*4882a593Smuzhiyun }
103*4882a593Smuzhiyun 
104*4882a593Smuzhiyun #ifdef CONFIG_BCM47XX_SSB
bcm47xx_register_ssb(void)105*4882a593Smuzhiyun static void __init bcm47xx_register_ssb(void)
106*4882a593Smuzhiyun {
107*4882a593Smuzhiyun 	int err;
108*4882a593Smuzhiyun 	char buf[100];
109*4882a593Smuzhiyun 	struct ssb_mipscore *mcore;
110*4882a593Smuzhiyun 
111*4882a593Smuzhiyun 	err = ssb_bus_host_soc_register(&bcm47xx_bus.ssb, SSB_ENUM_BASE);
112*4882a593Smuzhiyun 	if (err)
113*4882a593Smuzhiyun 		panic("Failed to initialize SSB bus (err %d)", err);
114*4882a593Smuzhiyun 
115*4882a593Smuzhiyun 	mcore = &bcm47xx_bus.ssb.mipscore;
116*4882a593Smuzhiyun 	if (bcm47xx_nvram_getenv("kernel_args", buf, sizeof(buf)) >= 0) {
117*4882a593Smuzhiyun 		if (strstr(buf, "console=ttyS1")) {
118*4882a593Smuzhiyun 			struct ssb_serial_port port;
119*4882a593Smuzhiyun 
120*4882a593Smuzhiyun 			pr_debug("Swapping serial ports!\n");
121*4882a593Smuzhiyun 			/* swap serial ports */
122*4882a593Smuzhiyun 			memcpy(&port, &mcore->serial_ports[0], sizeof(port));
123*4882a593Smuzhiyun 			memcpy(&mcore->serial_ports[0], &mcore->serial_ports[1],
124*4882a593Smuzhiyun 			       sizeof(port));
125*4882a593Smuzhiyun 			memcpy(&mcore->serial_ports[1], &port, sizeof(port));
126*4882a593Smuzhiyun 		}
127*4882a593Smuzhiyun 	}
128*4882a593Smuzhiyun }
129*4882a593Smuzhiyun #endif
130*4882a593Smuzhiyun 
131*4882a593Smuzhiyun #ifdef CONFIG_BCM47XX_BCMA
bcm47xx_register_bcma(void)132*4882a593Smuzhiyun static void __init bcm47xx_register_bcma(void)
133*4882a593Smuzhiyun {
134*4882a593Smuzhiyun 	int err;
135*4882a593Smuzhiyun 
136*4882a593Smuzhiyun 	err = bcma_host_soc_register(&bcm47xx_bus.bcma);
137*4882a593Smuzhiyun 	if (err)
138*4882a593Smuzhiyun 		panic("Failed to register BCMA bus (err %d)", err);
139*4882a593Smuzhiyun }
140*4882a593Smuzhiyun #endif
141*4882a593Smuzhiyun 
142*4882a593Smuzhiyun /*
143*4882a593Smuzhiyun  * Memory setup is done in the early part of MIPS's arch_mem_init. It's supposed
144*4882a593Smuzhiyun  * to detect memory and record it with memblock_add.
145*4882a593Smuzhiyun  * Any extra initializaion performed here must not use kmalloc or bootmem.
146*4882a593Smuzhiyun  */
plat_mem_setup(void)147*4882a593Smuzhiyun void __init plat_mem_setup(void)
148*4882a593Smuzhiyun {
149*4882a593Smuzhiyun 	struct cpuinfo_mips *c = &current_cpu_data;
150*4882a593Smuzhiyun 
151*4882a593Smuzhiyun 	if (c->cputype == CPU_74K) {
152*4882a593Smuzhiyun 		pr_info("Using bcma bus\n");
153*4882a593Smuzhiyun #ifdef CONFIG_BCM47XX_BCMA
154*4882a593Smuzhiyun 		bcm47xx_bus_type = BCM47XX_BUS_TYPE_BCMA;
155*4882a593Smuzhiyun 		bcm47xx_register_bcma();
156*4882a593Smuzhiyun 		bcm47xx_set_system_type(bcm47xx_bus.bcma.bus.chipinfo.id);
157*4882a593Smuzhiyun #ifdef CONFIG_HIGHMEM
158*4882a593Smuzhiyun 		bcm47xx_prom_highmem_init();
159*4882a593Smuzhiyun #endif
160*4882a593Smuzhiyun #endif
161*4882a593Smuzhiyun 	} else {
162*4882a593Smuzhiyun 		pr_info("Using ssb bus\n");
163*4882a593Smuzhiyun #ifdef CONFIG_BCM47XX_SSB
164*4882a593Smuzhiyun 		bcm47xx_bus_type = BCM47XX_BUS_TYPE_SSB;
165*4882a593Smuzhiyun 		bcm47xx_sprom_register_fallbacks();
166*4882a593Smuzhiyun 		bcm47xx_register_ssb();
167*4882a593Smuzhiyun 		bcm47xx_set_system_type(bcm47xx_bus.ssb.chip_id);
168*4882a593Smuzhiyun #endif
169*4882a593Smuzhiyun 	}
170*4882a593Smuzhiyun 
171*4882a593Smuzhiyun 	_machine_restart = bcm47xx_machine_restart;
172*4882a593Smuzhiyun 	_machine_halt = bcm47xx_machine_halt;
173*4882a593Smuzhiyun 	pm_power_off = bcm47xx_machine_halt;
174*4882a593Smuzhiyun }
175*4882a593Smuzhiyun 
176*4882a593Smuzhiyun #ifdef CONFIG_BCM47XX_BCMA
bcm47xx_setup_device(void)177*4882a593Smuzhiyun static struct device * __init bcm47xx_setup_device(void)
178*4882a593Smuzhiyun {
179*4882a593Smuzhiyun 	struct device *dev;
180*4882a593Smuzhiyun 	int err;
181*4882a593Smuzhiyun 
182*4882a593Smuzhiyun 	dev = kzalloc(sizeof(*dev), GFP_KERNEL);
183*4882a593Smuzhiyun 	if (!dev)
184*4882a593Smuzhiyun 		return NULL;
185*4882a593Smuzhiyun 
186*4882a593Smuzhiyun 	err = dev_set_name(dev, "bcm47xx_soc");
187*4882a593Smuzhiyun 	if (err) {
188*4882a593Smuzhiyun 		pr_err("Failed to set SoC device name: %d\n", err);
189*4882a593Smuzhiyun 		kfree(dev);
190*4882a593Smuzhiyun 		return NULL;
191*4882a593Smuzhiyun 	}
192*4882a593Smuzhiyun 
193*4882a593Smuzhiyun 	err = dma_coerce_mask_and_coherent(dev, DMA_BIT_MASK(32));
194*4882a593Smuzhiyun 	if (err)
195*4882a593Smuzhiyun 		pr_err("Failed to set SoC DMA mask: %d\n", err);
196*4882a593Smuzhiyun 
197*4882a593Smuzhiyun 	return dev;
198*4882a593Smuzhiyun }
199*4882a593Smuzhiyun #endif
200*4882a593Smuzhiyun 
201*4882a593Smuzhiyun /*
202*4882a593Smuzhiyun  * This finishes bus initialization doing things that were not possible without
203*4882a593Smuzhiyun  * kmalloc. Make sure to call it late enough (after mm_init).
204*4882a593Smuzhiyun  */
bcm47xx_bus_setup(void)205*4882a593Smuzhiyun void __init bcm47xx_bus_setup(void)
206*4882a593Smuzhiyun {
207*4882a593Smuzhiyun #ifdef CONFIG_BCM47XX_BCMA
208*4882a593Smuzhiyun 	if (bcm47xx_bus_type == BCM47XX_BUS_TYPE_BCMA) {
209*4882a593Smuzhiyun 		int err;
210*4882a593Smuzhiyun 
211*4882a593Smuzhiyun 		bcm47xx_bus.bcma.dev = bcm47xx_setup_device();
212*4882a593Smuzhiyun 		if (!bcm47xx_bus.bcma.dev)
213*4882a593Smuzhiyun 			panic("Failed to setup SoC device\n");
214*4882a593Smuzhiyun 
215*4882a593Smuzhiyun 		err = bcma_host_soc_init(&bcm47xx_bus.bcma);
216*4882a593Smuzhiyun 		if (err)
217*4882a593Smuzhiyun 			panic("Failed to initialize BCMA bus (err %d)", err);
218*4882a593Smuzhiyun 	}
219*4882a593Smuzhiyun #endif
220*4882a593Smuzhiyun 
221*4882a593Smuzhiyun 	/* With bus initialized we can access NVRAM and detect the board */
222*4882a593Smuzhiyun 	bcm47xx_board_detect();
223*4882a593Smuzhiyun 	mips_set_machine_name(bcm47xx_board_get_name());
224*4882a593Smuzhiyun }
225*4882a593Smuzhiyun 
bcm47xx_cpu_fixes(void)226*4882a593Smuzhiyun static int __init bcm47xx_cpu_fixes(void)
227*4882a593Smuzhiyun {
228*4882a593Smuzhiyun 	switch (bcm47xx_bus_type) {
229*4882a593Smuzhiyun #ifdef CONFIG_BCM47XX_SSB
230*4882a593Smuzhiyun 	case BCM47XX_BUS_TYPE_SSB:
231*4882a593Smuzhiyun 		/* Nothing to do */
232*4882a593Smuzhiyun 		break;
233*4882a593Smuzhiyun #endif
234*4882a593Smuzhiyun #ifdef CONFIG_BCM47XX_BCMA
235*4882a593Smuzhiyun 	case BCM47XX_BUS_TYPE_BCMA:
236*4882a593Smuzhiyun 		/* The BCM4706 has a problem with the CPU wait instruction.
237*4882a593Smuzhiyun 		 * When r4k_wait or r4k_wait_irqoff is used will just hang and
238*4882a593Smuzhiyun 		 * not return from a msleep(). Removing the cpu_wait
239*4882a593Smuzhiyun 		 * functionality is a workaround for this problem. The BCM4716
240*4882a593Smuzhiyun 		 * does not have this problem.
241*4882a593Smuzhiyun 		 */
242*4882a593Smuzhiyun 		if (bcm47xx_bus.bcma.bus.chipinfo.id == BCMA_CHIP_ID_BCM4706)
243*4882a593Smuzhiyun 			cpu_wait = NULL;
244*4882a593Smuzhiyun 		break;
245*4882a593Smuzhiyun #endif
246*4882a593Smuzhiyun 	}
247*4882a593Smuzhiyun 	return 0;
248*4882a593Smuzhiyun }
249*4882a593Smuzhiyun arch_initcall(bcm47xx_cpu_fixes);
250*4882a593Smuzhiyun 
251*4882a593Smuzhiyun static struct fixed_phy_status bcm47xx_fixed_phy_status __initdata = {
252*4882a593Smuzhiyun 	.link	= 1,
253*4882a593Smuzhiyun 	.speed	= SPEED_100,
254*4882a593Smuzhiyun 	.duplex	= DUPLEX_FULL,
255*4882a593Smuzhiyun };
256*4882a593Smuzhiyun 
bcm47xx_register_bus_complete(void)257*4882a593Smuzhiyun static int __init bcm47xx_register_bus_complete(void)
258*4882a593Smuzhiyun {
259*4882a593Smuzhiyun 	switch (bcm47xx_bus_type) {
260*4882a593Smuzhiyun #ifdef CONFIG_BCM47XX_SSB
261*4882a593Smuzhiyun 	case BCM47XX_BUS_TYPE_SSB:
262*4882a593Smuzhiyun 		/* Nothing to do */
263*4882a593Smuzhiyun 		break;
264*4882a593Smuzhiyun #endif
265*4882a593Smuzhiyun #ifdef CONFIG_BCM47XX_BCMA
266*4882a593Smuzhiyun 	case BCM47XX_BUS_TYPE_BCMA:
267*4882a593Smuzhiyun 		if (device_register(bcm47xx_bus.bcma.dev))
268*4882a593Smuzhiyun 			pr_err("Failed to register SoC device\n");
269*4882a593Smuzhiyun 		bcma_bus_register(&bcm47xx_bus.bcma.bus);
270*4882a593Smuzhiyun 		break;
271*4882a593Smuzhiyun #endif
272*4882a593Smuzhiyun 	}
273*4882a593Smuzhiyun 	bcm47xx_buttons_register();
274*4882a593Smuzhiyun 	bcm47xx_leds_register();
275*4882a593Smuzhiyun 	bcm47xx_workarounds();
276*4882a593Smuzhiyun 
277*4882a593Smuzhiyun 	fixed_phy_add(PHY_POLL, 0, &bcm47xx_fixed_phy_status);
278*4882a593Smuzhiyun 	return 0;
279*4882a593Smuzhiyun }
280*4882a593Smuzhiyun device_initcall(bcm47xx_register_bus_complete);
281