| David Gibson | f6dfc80 | 2007-05-08 14:10:01 +1000 | [diff] [blame] | 1 | /* | 
 | 2 |  * Copyright 2007 David Gibson, IBM Corporation. | 
 | 3 |  * | 
 | 4 |  * Based on earlier code: | 
 | 5 |  *   Copyright (C) Paul Mackerras 1997. | 
 | 6 |  * | 
 | 7 |  *   Matt Porter <mporter@kernel.crashing.org> | 
 | 8 |  *   Copyright 2002-2005 MontaVista Software Inc. | 
 | 9 |  * | 
 | 10 |  *   Eugene Surovegin <eugene.surovegin@zultys.com> or <ebs@ebshome.net> | 
 | 11 |  *   Copyright (c) 2003, 2004 Zultys Technologies | 
 | 12 |  * | 
 | 13 |  * This program is free software; you can redistribute it and/or | 
 | 14 |  * modify it under the terms of the GNU General Public License | 
 | 15 |  * as published by the Free Software Foundation; either version | 
 | 16 |  * 2 of the License, or (at your option) any later version. | 
 | 17 |  */ | 
 | 18 | #include <stdarg.h> | 
 | 19 | #include <stddef.h> | 
 | 20 | #include "types.h" | 
 | 21 | #include "elf.h" | 
 | 22 | #include "string.h" | 
 | 23 | #include "stdio.h" | 
 | 24 | #include "page.h" | 
 | 25 | #include "ops.h" | 
 | 26 | #include "reg.h" | 
| David Gibson | 0d279d4 | 2007-07-30 15:55:02 +1000 | [diff] [blame] | 27 | #include "io.h" | 
| David Gibson | f6dfc80 | 2007-05-08 14:10:01 +1000 | [diff] [blame] | 28 | #include "dcr.h" | 
| Josh Boyer | e90f3b7 | 2007-08-20 07:28:30 -0500 | [diff] [blame] | 29 | #include "4xx.h" | 
| David Gibson | f6dfc80 | 2007-05-08 14:10:01 +1000 | [diff] [blame] | 30 | #include "44x.h" | 
 | 31 |  | 
| David Gibson | f6dfc80 | 2007-05-08 14:10:01 +1000 | [diff] [blame] | 32 | static u8 *ebony_mac0, *ebony_mac1; | 
 | 33 |  | 
 | 34 | /* Calculate 440GP clocks */ | 
 | 35 | void ibm440gp_fixup_clocks(unsigned int sysclk, unsigned int ser_clk) | 
 | 36 | { | 
 | 37 | 	u32 sys0 = mfdcr(DCRN_CPC0_SYS0); | 
 | 38 | 	u32 cr0 = mfdcr(DCRN_CPC0_CR0); | 
 | 39 | 	u32 cpu, plb, opb, ebc, tb, uart0, uart1, m; | 
 | 40 | 	u32 opdv = CPC0_SYS0_OPDV(sys0); | 
 | 41 | 	u32 epdv = CPC0_SYS0_EPDV(sys0); | 
 | 42 |  | 
 | 43 | 	if (sys0 & CPC0_SYS0_BYPASS) { | 
 | 44 | 		/* Bypass system PLL */ | 
 | 45 | 		cpu = plb = sysclk; | 
 | 46 | 	} else { | 
 | 47 | 		if (sys0 & CPC0_SYS0_EXTSL) | 
 | 48 | 			/* PerClk */ | 
 | 49 | 			m = CPC0_SYS0_FWDVB(sys0) * opdv * epdv; | 
 | 50 | 		else | 
 | 51 | 			/* CPU clock */ | 
 | 52 | 			m = CPC0_SYS0_FBDV(sys0) * CPC0_SYS0_FWDVA(sys0); | 
 | 53 | 		cpu = sysclk * m / CPC0_SYS0_FWDVA(sys0); | 
 | 54 | 		plb = sysclk * m / CPC0_SYS0_FWDVB(sys0); | 
 | 55 | 	} | 
 | 56 |  | 
 | 57 | 	opb = plb / opdv; | 
 | 58 | 	ebc = opb / epdv; | 
 | 59 |  | 
 | 60 | 	/* FIXME: Check if this is for all 440GP, or just Ebony */ | 
 | 61 | 	if ((mfpvr() & 0xf0000fff) == 0x40000440) | 
 | 62 | 		/* Rev. B 440GP, use external system clock */ | 
 | 63 | 		tb = sysclk; | 
 | 64 | 	else | 
 | 65 | 		/* Rev. C 440GP, errata force us to use internal clock */ | 
 | 66 | 		tb = cpu; | 
 | 67 |  | 
 | 68 | 	if (cr0 & CPC0_CR0_U0EC) | 
 | 69 | 		/* External UART clock */ | 
 | 70 | 		uart0 = ser_clk; | 
 | 71 | 	else | 
 | 72 | 		/* Internal UART clock */ | 
 | 73 | 		uart0 = plb / CPC0_CR0_UDIV(cr0); | 
 | 74 |  | 
 | 75 | 	if (cr0 & CPC0_CR0_U1EC) | 
 | 76 | 		/* External UART clock */ | 
 | 77 | 		uart1 = ser_clk; | 
 | 78 | 	else | 
 | 79 | 		/* Internal UART clock */ | 
 | 80 | 		uart1 = plb / CPC0_CR0_UDIV(cr0); | 
 | 81 |  | 
 | 82 | 	printf("PPC440GP: SysClk = %dMHz (%x)\n\r", | 
 | 83 | 	       (sysclk + 500000) / 1000000, sysclk); | 
 | 84 |  | 
 | 85 | 	dt_fixup_cpu_clocks(cpu, tb, 0); | 
 | 86 |  | 
 | 87 | 	dt_fixup_clock("/plb", plb); | 
 | 88 | 	dt_fixup_clock("/plb/opb", opb); | 
 | 89 | 	dt_fixup_clock("/plb/opb/ebc", ebc); | 
 | 90 | 	dt_fixup_clock("/plb/opb/serial@40000200", uart0); | 
 | 91 | 	dt_fixup_clock("/plb/opb/serial@40000300", uart1); | 
 | 92 | } | 
 | 93 |  | 
| David Gibson | 0d279d4 | 2007-07-30 15:55:02 +1000 | [diff] [blame] | 94 | #define EBONY_FPGA_PATH		"/plb/opb/ebc/fpga" | 
 | 95 | #define	EBONY_FPGA_FLASH_SEL	0x01 | 
 | 96 | #define EBONY_SMALL_FLASH_PATH	"/plb/opb/ebc/small-flash" | 
 | 97 |  | 
 | 98 | static void ebony_flashsel_fixup(void) | 
 | 99 | { | 
 | 100 | 	void *devp; | 
 | 101 | 	u32 reg[3] = {0x0, 0x0, 0x80000}; | 
 | 102 | 	u8 *fpga; | 
 | 103 | 	u8 fpga_reg0 = 0x0; | 
 | 104 |  | 
 | 105 | 	devp = finddevice(EBONY_FPGA_PATH); | 
 | 106 | 	if (!devp) | 
 | 107 | 		fatal("Couldn't locate FPGA node %s\n\r", EBONY_FPGA_PATH); | 
 | 108 |  | 
 | 109 | 	if (getprop(devp, "virtual-reg", &fpga, sizeof(fpga)) != sizeof(fpga)) | 
 | 110 | 		fatal("%s has missing or invalid virtual-reg property\n\r", | 
 | 111 | 		      EBONY_FPGA_PATH); | 
 | 112 |  | 
 | 113 | 	fpga_reg0 = in_8(fpga); | 
 | 114 |  | 
 | 115 | 	devp = finddevice(EBONY_SMALL_FLASH_PATH); | 
 | 116 | 	if (!devp) | 
 | 117 | 		fatal("Couldn't locate small flash node %s\n\r", | 
 | 118 | 		      EBONY_SMALL_FLASH_PATH); | 
 | 119 |  | 
 | 120 | 	if (getprop(devp, "reg", reg, sizeof(reg)) != sizeof(reg)) | 
 | 121 | 		fatal("%s has reg property of unexpected size\n\r", | 
 | 122 | 		      EBONY_SMALL_FLASH_PATH); | 
 | 123 |  | 
 | 124 | 	/* Invert address bit 14 (IBM-endian) if FLASH_SEL fpga bit is set */ | 
 | 125 | 	if (fpga_reg0 & EBONY_FPGA_FLASH_SEL) | 
 | 126 | 		reg[1] ^= 0x80000; | 
 | 127 |  | 
 | 128 | 	setprop(devp, "reg", reg, sizeof(reg)); | 
 | 129 | } | 
 | 130 |  | 
| David Gibson | f6dfc80 | 2007-05-08 14:10:01 +1000 | [diff] [blame] | 131 | static void ebony_fixups(void) | 
 | 132 | { | 
 | 133 | 	// FIXME: sysclk should be derived by reading the FPGA registers | 
 | 134 | 	unsigned long sysclk = 33000000; | 
 | 135 |  | 
 | 136 | 	ibm440gp_fixup_clocks(sysclk, 6 * 1843200); | 
| Josh Boyer | e90f3b7 | 2007-08-20 07:28:30 -0500 | [diff] [blame] | 137 | 	ibm4xx_fixup_memsize(); | 
| David Gibson | f6dfc80 | 2007-05-08 14:10:01 +1000 | [diff] [blame] | 138 | 	dt_fixup_mac_addresses(ebony_mac0, ebony_mac1); | 
| David Gibson | b2ba34f | 2007-06-13 14:52:59 +1000 | [diff] [blame] | 139 | 	ibm4xx_fixup_ebc_ranges("/plb/opb/ebc"); | 
| David Gibson | 0d279d4 | 2007-07-30 15:55:02 +1000 | [diff] [blame] | 140 | 	ebony_flashsel_fixup(); | 
| David Gibson | f6dfc80 | 2007-05-08 14:10:01 +1000 | [diff] [blame] | 141 | } | 
 | 142 |  | 
| David Gibson | f6dfc80 | 2007-05-08 14:10:01 +1000 | [diff] [blame] | 143 | void ebony_init(void *mac0, void *mac1) | 
 | 144 | { | 
 | 145 | 	platform_ops.fixups = ebony_fixups; | 
| David Gibson | 1112334 | 2007-06-13 14:52:58 +1000 | [diff] [blame] | 146 | 	platform_ops.exit = ibm44x_dbcr_reset; | 
| David Gibson | f6dfc80 | 2007-05-08 14:10:01 +1000 | [diff] [blame] | 147 | 	ebony_mac0 = mac0; | 
 | 148 | 	ebony_mac1 = mac1; | 
 | 149 | 	ft_init(_dtb_start, _dtb_end - _dtb_start, 32); | 
 | 150 | 	serial_console_init(); | 
 | 151 | } |