[PATCH][PPC32] Add U-Boot support to Ocotea/440GX port
Matt Porter
mporter at kernel.crashing.org
Tue Oct 5 09:37:19 EST 2004
Adds support for booting the same Ocotea kernel from either the
default PIBS f/w or U-Boot.
Signed-off-by: Matt Porter <mporter at kernel.crashing.org>
diff -Nru a/arch/ppc/boot/simple/Makefile b/arch/ppc/boot/simple/Makefile
--- a/arch/ppc/boot/simple/Makefile 2004-10-04 16:31:26 -07:00
+++ b/arch/ppc/boot/simple/Makefile 2004-10-04 16:31:26 -07:00
@@ -64,6 +64,7 @@
zimageinitrd-$(CONFIG_OCOTEA) := zImage.initrd-TREE
end-$(CONFIG_OCOTEA) := ocotea
entrypoint-$(CONFIG_OCOTEA) := 0x01000000
+ extra.o-$(CONFIG_OCOTEA) := pibs.o
extra.o-$(CONFIG_EV64260) := direct.o misc-ev64260.o
end-$(CONFIG_EV64260) := ev64260
diff -Nru a/arch/ppc/boot/simple/pibs.c b/arch/ppc/boot/simple/pibs.c
--- /dev/null Wed Dec 31 16:00:00 196900
+++ b/arch/ppc/boot/simple/pibs.c 2004-10-04 16:31:26 -07:00
@@ -0,0 +1,101 @@
+/*
+ * 2004 (c) MontaVista, Software, Inc. This file is licensed under
+ * the terms of the GNU General Public License version 2. This program
+ * is licensed "as is" without any warranty of any kind, whether express
+ * or implied.
+ */
+
+#include <linux/types.h>
+#include <linux/config.h>
+#include <linux/string.h>
+#include <linux/ctype.h>
+#include <asm/ppcboot.h>
+#include <platforms/4xx/ocotea.h>
+
+extern unsigned long decompress_kernel(unsigned long load_addr, int num_words,
+ unsigned long cksum);
+
+/* We need to make sure that this is before the images to ensure
+ * that it's in a mapped location. - Tom */
+bd_t hold_resid_buf __attribute__ ((__section__ (".data.boot")));
+bd_t *hold_residual = &hold_resid_buf;
+
+/* String functions lifted from lib/vsprintf.c and lib/ctype.c */
+unsigned char _ctype[] = {
+_C,_C,_C,_C,_C,_C,_C,_C, /* 0-7 */
+_C,_C|_S,_C|_S,_C|_S,_C|_S,_C|_S,_C,_C, /* 8-15 */
+_C,_C,_C,_C,_C,_C,_C,_C, /* 16-23 */
+_C,_C,_C,_C,_C,_C,_C,_C, /* 24-31 */
+_S|_SP,_P,_P,_P,_P,_P,_P,_P, /* 32-39 */
+_P,_P,_P,_P,_P,_P,_P,_P, /* 40-47 */
+_D,_D,_D,_D,_D,_D,_D,_D, /* 48-55 */
+_D,_D,_P,_P,_P,_P,_P,_P, /* 56-63 */
+_P,_U|_X,_U|_X,_U|_X,_U|_X,_U|_X,_U|_X,_U, /* 64-71 */
+_U,_U,_U,_U,_U,_U,_U,_U, /* 72-79 */
+_U,_U,_U,_U,_U,_U,_U,_U, /* 80-87 */
+_U,_U,_U,_P,_P,_P,_P,_P, /* 88-95 */
+_P,_L|_X,_L|_X,_L|_X,_L|_X,_L|_X,_L|_X,_L, /* 96-103 */
+_L,_L,_L,_L,_L,_L,_L,_L, /* 104-111 */
+_L,_L,_L,_L,_L,_L,_L,_L, /* 112-119 */
+_L,_L,_L,_P,_P,_P,_P,_C, /* 120-127 */
+0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, /* 128-143 */
+0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, /* 144-159 */
+_S|_SP,_P,_P,_P,_P,_P,_P,_P,_P,_P,_P,_P,_P,_P,_P,_P, /* 160-175 */
+_P,_P,_P,_P,_P,_P,_P,_P,_P,_P,_P,_P,_P,_P,_P,_P, /* 176-191 */
+_U,_U,_U,_U,_U,_U,_U,_U,_U,_U,_U,_U,_U,_U,_U,_U, /* 192-207 */
+_U,_U,_U,_U,_U,_U,_U,_P,_U,_U,_U,_U,_U,_U,_U,_L, /* 208-223 */
+_L,_L,_L,_L,_L,_L,_L,_L,_L,_L,_L,_L,_L,_L,_L,_L, /* 224-239 */
+_L,_L,_L,_L,_L,_L,_L,_P,_L,_L,_L,_L,_L,_L,_L,_L}; /* 240-255 */
+
+/**
+ * simple_strtoull - convert a string to an unsigned long long
+ * @cp: The start of the string
+ * @endp: A pointer to the end of the parsed string will be placed here
+ * @base: The number base to use
+ */
+unsigned long long simple_strtoull(const char *cp,char **endp,unsigned int base)
+{
+ unsigned long long result = 0,value;
+
+ if (!base) {
+ base = 10;
+ if (*cp == '0') {
+ base = 8;
+ cp++;
+ if ((toupper(*cp) == 'X') && isxdigit(cp[1])) {
+ cp++;
+ base = 16;
+ }
+ }
+ } else if (base == 16) {
+ if (cp[0] == '0' && toupper(cp[1]) == 'X')
+ cp += 2;
+ }
+ while (isxdigit(*cp) && (value = isdigit(*cp) ? *cp-'0' : (islower(*cp)
+ ? toupper(*cp) : *cp)-'A'+10) < base) {
+ result = result*base + value;
+ cp++;
+ }
+ if (endp)
+ *endp = (char *)cp;
+ return result;
+}
+
+void *
+load_kernel(unsigned long load_addr, int num_words, unsigned long cksum,
+ void *ign1, void *ign2)
+{
+ unsigned long long mac64;
+
+ decompress_kernel(load_addr, num_words, cksum);
+
+ mac64 = simple_strtoull((char *)OCOTEA_PIBS_MAC_BASE, 0, 16);
+ memcpy(hold_residual->bi_enetaddr, (char *)&mac64+2, 6);
+ mac64 = simple_strtoull((char *)(OCOTEA_PIBS_MAC_BASE+OCOTEA_PIBS_MAC_OFFSET), 0, 16);
+ memcpy(hold_residual->bi_enet1addr, (char *)&mac64+2, 6);
+ mac64 = simple_strtoull((char *)(OCOTEA_PIBS_MAC_BASE+OCOTEA_PIBS_MAC_OFFSET*2), 0, 16);
+ memcpy(hold_residual->bi_enet2addr, (char *)&mac64+2, 6);
+ mac64 = simple_strtoull((char *)(OCOTEA_PIBS_MAC_BASE+OCOTEA_PIBS_MAC_OFFSET*3), 0, 16);
+ memcpy(hold_residual->bi_enet3addr, (char *)&mac64+2, 6);
+ return (void *)hold_residual;
+}
diff -Nru a/arch/ppc/platforms/4xx/ocotea.c b/arch/ppc/platforms/4xx/ocotea.c
--- a/arch/ppc/platforms/4xx/ocotea.c 2004-10-04 16:31:26 -07:00
+++ b/arch/ppc/platforms/4xx/ocotea.c 2004-10-04 16:31:26 -07:00
@@ -47,6 +47,7 @@
#include <asm/todc.h>
#include <asm/bootinfo.h>
#include <asm/ppc4xx_pic.h>
+#include <asm/ppcboot.h>
#include <syslib/ibm440gx_common.h>
@@ -58,13 +59,25 @@
#include "../../../../drivers/net/ibm_emac/ibm_emac_phy.h"
extern void abort(void);
+bd_t __res;
+
+static struct ibm44x_clocks clocks;
+
+static int __init
+ocotea_get_dec_freq(void)
+{
+ if (mfspr(SPRN_CCR1) & CCR1_TCS)
+ return OCOTEA_TMR_CLK;
+ else
+ return clocks.cpu;
+}
static void __init
ocotea_calibrate_decr(void)
{
unsigned int freq;
- freq = OCOTEA_SYSCLK;
+ freq = ocotea_get_dec_freq();
tb_ticks_per_jiffy = freq / HZ;
tb_to_us = mulhwu_scale_factor(freq, 1000000);
@@ -107,6 +120,46 @@
return PCI_IRQ_TABLE_LOOKUP;
}
+static void __init ocotea_set_emacdata(void)
+{
+ struct ocp_def *def;
+ struct ocp_func_emac_data *emacdata;
+ int i;
+
+ /*
+ * Note: Current rev. board only operates in Group 4a
+ * mode, so we always set EMAC0-1 for SMII and EMAC2-3
+ * for RGMII (though these could run in RTBI just the same).
+ *
+ * The FPGA reg 3 information isn't even suitable for
+ * determining the phy_mode, so if the board becomes
+ * usable in !4a, it will be necessary to parse an environment
+ * variable from the firmware or similar to properly configure
+ * the phy_map/phy_mode.
+ */
+ /* Set phy_map, phy_mode, and mac_addr for each EMAC */
+ for (i=0; i<4; i++) {
+ def = ocp_get_one_device(OCP_VENDOR_IBM, OCP_FUNC_EMAC, i);
+ emacdata = def->additions;
+ if (i < 2) {
+ emacdata->phy_map = 0x00000001; /* Skip 0x00 */
+ emacdata->phy_mode = PHY_MODE_SMII;
+ }
+ else {
+ emacdata->phy_map = 0x0000ffff; /* Skip 0x00-0x0f */
+ emacdata->phy_mode = PHY_MODE_RGMII;
+ }
+ if (i == 0)
+ memcpy(emacdata->mac_addr, __res.bi_enetaddr, 6);
+ else if (i == 1)
+ memcpy(emacdata->mac_addr, __res.bi_enet1addr, 6);
+ else if (i == 2)
+ memcpy(emacdata->mac_addr, __res.bi_enet2addr, 6);
+ else if (i == 3)
+ memcpy(emacdata->mac_addr, __res.bi_enet3addr, 6);
+ }
+}
+
#define PCIX_READW(offset) \
(readw((u32)pcix_reg_base+offset))
@@ -209,7 +262,7 @@
TODC_ALLOC();
static void __init
-ocotea_early_serial_map(const struct ibm44x_clocks *clks)
+ocotea_early_serial_map(void)
{
struct uart_port port;
@@ -217,7 +270,7 @@
memset(&port, 0, sizeof(port));
port.membase = ioremap64(PPC440GX_UART0_ADDR, 8);
port.irq = UART0_INT;
- port.uartclk = clks->uart0;
+ port.uartclk = clocks.uart0;
port.regshift = 0;
port.iotype = SERIAL_IO_MEM;
port.flags = ASYNC_BOOT_AUTOCONF | ASYNC_SKIP_TEST;
@@ -229,7 +282,7 @@
port.membase = ioremap64(PPC440GX_UART1_ADDR, 8);
port.irq = UART1_INT;
- port.uartclk = clks->uart1;
+ port.uartclk = clocks.uart1;
port.line = 1;
if (early_serial_setup(&port) != 0) {
@@ -240,41 +293,7 @@
static void __init
ocotea_setup_arch(void)
{
- unsigned char *addr;
- unsigned long long mac64;
- struct ocp_def *def;
- struct ocp_func_emac_data *emacdata;
- int i;
- struct ibm44x_clocks clocks;
-
- /*
- * Note: Current rev. board only operates in Group 4a
- * mode, so we always set EMAC0-1 for SMII and EMAC2-3
- * for RGMII (though these could run in RTBI just the same).
- *
- * The FPGA reg 3 information isn't even suitable for
- * determining the phy_mode, so if the board becomes
- * usable in !4a, it will be necessary to parse an environment
- * variable from the firmware or similar to properly configure
- * the phy_map/phy_mode.
- */
- /* Set phy_map, phy_mode, and mac_addr for each EMAC */
- addr = ioremap64(OCOTEA_MAC_BASE, OCOTEA_MAC_SIZE);
- for (i=0; i<4; i++) {
- mac64 = simple_strtoull(addr+OCOTEA_MAC_OFFSET*i, 0, 16);
- def = ocp_get_one_device(OCP_VENDOR_IBM, OCP_FUNC_EMAC, i);
- emacdata = def->additions;
- if (i < 2) {
- emacdata->phy_map = 0x00000001; /* Skip 0x00 */
- emacdata->phy_mode = PHY_MODE_SMII;
- }
- else {
- emacdata->phy_map = 0x0000ffff; /* Skip 0x00-0x0f */
- emacdata->phy_mode = PHY_MODE_RGMII;
- }
- memcpy(emacdata->mac_addr, (char *)&mac64+2, 6);
- }
- iounmap(addr);
+ ocotea_set_emacdata();
ibm440gx_tah_enable();
@@ -319,7 +338,7 @@
ROOT_DEV = Root_HDA1;
#endif
- ocotea_early_serial_map(&clocks);
+ ocotea_early_serial_map();
/* Identify the system */
printk("IBM Ocotea port (MontaVista Software, Inc. <source at mvista.com>)\n");
@@ -454,19 +473,17 @@
}
#endif /* CONFIG_SERIAL_TEXT_DEBUG */
-#if 0
-static void __init
-ocotea_map_io(void)
-{
- io_block_mapping(0xe0000000, 0x0000000140000000,
- 0x00001000, _PAGE_IO);
-}
-#endif
-
void __init platform_init(unsigned long r3, unsigned long r4,
unsigned long r5, unsigned long r6, unsigned long r7)
{
- parse_bootinfo((struct bi_record *) (r3 + KERNELBASE));
+ parse_bootinfo(find_bootinfo());
+
+ /*
+ * If we were passed in a board information, copy it into the
+ * residual data area.
+ */
+ if (r3)
+ __res = *(bd_t *)(r3 + KERNELBASE);
/* Disable L2-Cache due to hardware issues */
ibm440gx_l2c_disable();
diff -Nru a/arch/ppc/platforms/4xx/ocotea.h b/arch/ppc/platforms/4xx/ocotea.h
--- a/arch/ppc/platforms/4xx/ocotea.h 2004-10-04 16:31:26 -07:00
+++ b/arch/ppc/platforms/4xx/ocotea.h 2004-10-04 16:31:26 -07:00
@@ -24,13 +24,14 @@
/* F/W TLB mapping used in bootloader glue to reset EMAC */
#define PPC44x_EMAC0_MR0 0xE0000800
-/* Location of MAC addresses in firmware */
-#define OCOTEA_MAC_BASE (OCOTEA_SMALL_FLASH_HIGH+0xb0500)
-#define OCOTEA_MAC_SIZE 0x200
-#define OCOTEA_MAC_OFFSET 0x100
+/* Location of MAC addresses in PIBS image */
+#define OCOTEA_PIBS_FLASH 0xfff00000
+#define OCOTEA_PIBS_MAC_BASE (OCOTEA_PIBS_FLASH+0xb0500)
+#define OCOTEA_PIBS_MAC_SIZE 0x200
+#define OCOTEA_PIBS_MAC_OFFSET 0x100
-/* Default clock rate */
-#define OCOTEA_SYSCLK 25000000
+/* External timer clock frequency */
+#define OCOTEA_TMR_CLK 25000000
/* RTC/NVRAM location */
#define OCOTEA_RTC_ADDR 0x0000000148000000ULL
diff -Nru a/include/asm-ppc/reg_booke.h b/include/asm-ppc/reg_booke.h
--- a/include/asm-ppc/reg_booke.h 2004-10-04 16:31:26 -07:00
+++ b/include/asm-ppc/reg_booke.h 2004-10-04 16:31:26 -07:00
@@ -123,9 +123,10 @@
#define SPRN_PID2 0x27A /* Process ID Register 2 */
#define SPRN_TLB0CFG 0x2B0 /* TLB 0 Config Register */
#define SPRN_TLB1CFG 0x2B1 /* TLB 1 Config Register */
+#define SPRN_CCR1 0x378 /* Core Configuration Register 1 */
#define SPRN_ZPR 0x3B0 /* Zone Protection Register (40x) */
#define SPRN_MMUCR 0x3B2 /* MMU Control Register */
-#define SPRN_CCR0 0x3B3 /* Core Configuration Register */
+#define SPRN_CCR0 0x3B3 /* Core Configuration Register 0 */
#define SPRN_SGR 0x3B9 /* Storage Guarded Register */
#define SPRN_DCWR 0x3BA /* Data Cache Write-thru Register */
#define SPRN_SLER 0x3BB /* Little-endian real mode */
@@ -178,6 +179,9 @@
#define SPRN_CSRR0 SPRN_SRR2 /* Critical Save and Restore Register 0 */
#define SPRN_CSRR1 SPRN_SRR3 /* Critical Save and Restore Register 1 */
#endif
+
+/* Bit definitions for CCR1. */
+#define CCR1_TCS 0x00000080 /* Timer Clock Select */
/* Bit definitions for the MCSR. */
#ifdef CONFIG_440A
More information about the Linuxppc-embedded
mailing list