Bootwrapper sources for Emerson Katana Qp Signed-off-by: Andrei Dolnikov <[EMAIL PROTECTED]>
--- Makefile | 3 cuboot-katanaqp.c | 470 ++++++++++++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 472 insertions(+), 1 deletion(-) diff --git a/arch/powerpc/boot/Makefile b/arch/powerpc/boot/Makefile index 18e3271..92b8fac 100644 --- a/arch/powerpc/boot/Makefile +++ b/arch/powerpc/boot/Makefile @@ -56,7 +56,7 @@ src-plat := of.c cuboot-52xx.c cuboot-83xx.c cuboot-85xx.c holly.c \ cuboot-ebony.c treeboot-ebony.c prpmc2800.c \ ps3-head.S ps3-hvcall.S ps3.c treeboot-bamboo.c cuboot-8xx.c \ cuboot-pq2.c cuboot-sequoia.c treeboot-walnut.c cuboot-bamboo.c \ - fixed-head.S ep88xc.c cuboot-hpc2.c + fixed-head.S ep88xc.c cuboot-hpc2.c cuboot-katanaqp.c src-boot := $(src-wlib) $(src-plat) empty.c src-boot := $(addprefix $(obj)/, $(src-boot)) @@ -159,6 +159,7 @@ image-$(CONFIG_EBONY) += treeImage.ebony cuImage.ebony image-$(CONFIG_BAMBOO) += treeImage.bamboo cuImage.bamboo image-$(CONFIG_SEQUOIA) += cuImage.sequoia image-$(CONFIG_WALNUT) += treeImage.walnut +image-$(CONFIG_PPC_KATANAQP) += cuImage.katanaqp endif # For 32-bit powermacs, build the COFF and miboot images diff --git a/arch/powerpc/boot/cuboot-katanaqp.c b/arch/powerpc/boot/cuboot-katanaqp.c new file mode 100644 index 0000000..19ba901 --- /dev/null +++ b/arch/powerpc/boot/cuboot-katanaqp.c @@ -0,0 +1,470 @@ +/* + * Emerson Katana Qp platform code. + * + * Authors: Vladislav Buzov <[EMAIL PROTECTED]> + * Andrei Dolnikov <[EMAIL PROTECTED]> + * + * Based on prpmc2800.c by Mark A. Greer <[EMAIL PROTECTED]> + * + * 2007 (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 <stdarg.h> +#include <stddef.h> +#include "cuboot.h" +#include "ppcboot.h" +#include "types.h" +#include "page.h" +#include "string.h" +#include "stdio.h" +#include "io.h" +#include "ops.h" +#include "mv64x60.h" + +#define Mb (1024U * 1024U) +#define Gb (Mb * 1024U) + +#define MHz (1000U * 1000U) +#define GHz (MHz * 1000U) + +#define BOARD_MODEL "Katana-Qp" +#define BOARD_MODEL_MAX 12 /* max strlen(BOARD_MODEL) + 1 */ +#define BOARD_CFG_MAX 28 /* max strlen(BOARD_CFG) + 1 */ +#define BOARD_MODEL_LEN (BOARD_MODEL_MAX + BOARD_CFG_MAX) + +#define MTD_PART_NODE "partition" +#define MTD_PART_NUM 3 +#define MTD_PART_NODE_LEN 20 +#define MTD_PART_MONITOR_SIZE (1*Mb) +#define MTD_PART_KERNEL_SIZE (2*Mb) + +/* + * CPLD registers definitions + */ +#define KATANAQP_CPLD_RCR 0x0004 /* Reset command */ +#define KATANAQP_CPLD_RCR_CPUHR (1 << 7) + +#define KATANAQP_CPLD_JSR 0x0020 /* Jumper settings */ +#define KATANAQP_CPLD_JSR_EBFM (1 << 6) + +#define KATANAQP_CPLD_PSR 0x0030 /* PCI status */ +#define KATANAQP_CPLD_PSR_PMCM (1 << 1) + +#define KATANAQP_CPLD_HCR 0x0044 /* Hardware config */ + +static bd_t bd; + +static u8 *bridge_base; +static u8 *cpld_base; + +typedef enum { + KATANAQP_UNKNOWN, + KATANAQP_CFG_PRPMC_SINGLE, + KATANAQP_CFG_PRPMC_DUAL, + KATANAQP_CFG_PT2CC_SINGLE, + KATANAQP_CFG_PT5CC_SINGLE, + KATANAQP_CFG_MEDIA_DUAL, + KATANAQP_CFG_PT2CC_DUAL, + KATANAQP_CFG_PT5CC_DUAL, + KATANAQP_CFG_PT5CC_CUSTOM, + KATANAQP_CFG_MEDIA_SINGLE, + KATANAQP_CFG_UNKNOWN, +} katanaqp_board_model; + +static katanaqp_board_model katanaqp_cfg; + +struct katanaqp_board_info { + char *cfg_name; + char eth_phys[3]; +}; + +struct katanaqp_mtd_part { + char *name; + u32 size; + u32 ro; +}; + +static struct katanaqp_board_info katanaqp_board_info[] = { + + [KATANAQP_CFG_PRPMC_SINGLE] = { + .cfg_name = "PrPMC Single Core", + .eth_phys = {10, 13, 6}, + }, + + [KATANAQP_CFG_PRPMC_DUAL] = { + .cfg_name = "PrPMC Dual Core", + .eth_phys = {10, 13, 6} + }, + + [KATANAQP_CFG_PT2CC_SINGLE] = { + .cfg_name = "PT2CC Single Core", + .eth_phys = {9, 8, 6}, + }, + + [KATANAQP_CFG_PT5CC_SINGLE] = { + .cfg_name = "PT5CC Single Core", + .eth_phys = {10, 13, 6}, + }, + + [KATANAQP_CFG_MEDIA_DUAL] = { + .cfg_name = "Dual Core Media Blade", + .eth_phys = {10, 13, 6}, + }, + + [KATANAQP_CFG_PT2CC_DUAL] = { + .cfg_name = "PT2CC Dual Core", + .eth_phys = {9, 8, 6}, + }, + + [KATANAQP_CFG_PT5CC_DUAL] = { + .cfg_name = "PT5CC Dual Core", + .eth_phys = {10, 13, 6}, + }, + + [KATANAQP_CFG_MEDIA_SINGLE] = { + .cfg_name = "Single Core Media Blade", + .eth_phys = {10, 13, 6}, + }, +}; + +/* + * Second flash bank partition layout. + */ +static struct katanaqp_mtd_part katanaqp_mtd_parts[MTD_PART_NUM] = { + { + .name = "Secondary Monitor", + .size = MTD_PART_MONITOR_SIZE, + .ro = 1, + }, + + { + .name = "Secondary Kernel", + .size = MTD_PART_KERNEL_SIZE, + }, + + { + /* Size depends on actual flash bank size */ + .name = "Secondary FS", + }, +}; + +static u8 *katanaqp_get_cpld_base(void) +{ + u32 v; + void *devp; + + devp = finddevice("cpld"); + if (devp == NULL) + fatal("Error: Missing CPLD device tree node\n\r"); + + if (getprop(devp, "virtual-reg", &v, sizeof(v)) != sizeof(v)) + fatal("Error: Can't get CPLD base address\n\r"); + + return (u8 *) v; +} + +static void katanaqp_get_cfg(void) +{ + katanaqp_cfg = in_8(cpld_base + KATANAQP_CPLD_HCR) & 0xf; + + if (katanaqp_cfg > 9) + katanaqp_cfg = KATANAQP_UNKNOWN; +} + +static int katanaqp_is_monarch(void) +{ + return !(in_8(cpld_base + KATANAQP_CPLD_PSR) & + KATANAQP_CPLD_PSR_PMCM); +} + +static void katanaqp_bridge_setup(void) +{ + u32 i, v[12], enables, acc_bits; + u32 pci_base_hi, pci_base_lo, size, buf[2]; + unsigned long cpu_base; + int rc; + void *devp; + u8 *bridge_pbase, is_coherent; + struct mv64x60_cpu2pci_win *tbl; + + bridge_pbase = mv64x60_get_bridge_pbase(); + is_coherent = mv64x60_is_coherent(); + + if (is_coherent) + acc_bits = MV64x60_PCI_ACC_CNTL_SNOOP_WB + | MV64x60_PCI_ACC_CNTL_SWAP_NONE + | MV64x60_PCI_ACC_CNTL_MBURST_32_BYTES + | MV64x60_PCI_ACC_CNTL_RDSIZE_32_BYTES; + else + acc_bits = MV64x60_PCI_ACC_CNTL_SNOOP_NONE + | MV64x60_PCI_ACC_CNTL_SWAP_NONE + | MV64x60_PCI_ACC_CNTL_MBURST_128_BYTES + | MV64x60_PCI_ACC_CNTL_RDSIZE_256_BYTES; + + /* + * MV64x60 boot code expects PCI host bridge to have 0 device + * number and access PCI configuration bridge registers by + * DEVFN(0, fn). This is not correct for bridges working in PCI-X + * mode since by default it has 0x1f device number stored in P2P + * configuration register. + */ + mv64x60_set_pci_bus(bridge_base, 1, 0, 0); + + mv64x60_config_ctlr_windows(bridge_base, bridge_pbase, is_coherent); + mv64x60_config_pci_windows(bridge_base, bridge_pbase, 1, 0, acc_bits); + + /* Get the cpu -> pci i/o & mem mappings from the device tree */ + devp = finddevice("/mv64x60/pci"); + if (devp == NULL) + fatal("Error: Missing /mv64x60/pci device tree node\n\r"); + + rc = getprop(devp, "ranges", v, sizeof(v)); + if (rc != sizeof(v)) + fatal("Error: Can't find /mv64x60/pci/ranges property\n\r"); + + /* Get the cpu -> pci i/o & mem mappings from the device tree */ + devp = finddevice("/mv64x60"); + if (devp == NULL) + fatal("Error: Missing /mv64x60 device tree node\n\r"); + + + enables = in_le32((u32 *) (bridge_base + MV64x60_CPU_BAR_ENABLE)); + enables |= 0x0007fe00; /* Disable all cpu->pci windows */ + out_le32((u32 *) (bridge_base + MV64x60_CPU_BAR_ENABLE), enables); + + for (i = 0; i < 12; i += 6) { + switch (v[i] & 0xff000000) { + case 0x01000000: /* PCI I/O Space */ + tbl = mv64x60_cpu2pci_io; + break; + case 0x02000000: /* PCI MEM Space */ + tbl = mv64x60_cpu2pci_mem; + break; + default: + continue; + } + + pci_base_hi = v[i + 1]; + pci_base_lo = v[i + 2]; + cpu_base = v[i + 3]; + size = v[i + 5]; + + buf[0] = cpu_base; + buf[1] = size; + + if (!dt_xlate_addr(devp, buf, sizeof(buf), &cpu_base)) + fatal("Error: Can't translate PCI address 0x%x\n\r", + (u32) cpu_base); + + mv64x60_config_cpu2pci_window(bridge_base, 1, pci_base_hi, + pci_base_lo, cpu_base, size, tbl); + } + + /* Enable cpu->pci1 i/o, cpu->pci1 mem0 */ + enables &= ~0x0000c000; + out_le32((u32 *) (bridge_base + MV64x60_CPU_BAR_ENABLE), enables); + +} + +/* + * Different Katana Qp configurations have different flash sizes varying + * from 16Mb to 64Mb. This routine determines an exact flash size and + * updates the device tree accordingly. + */ +static void katanaqp_flash_fixup(void) +{ + u32 flash0_size = 0, flash1_size = 0; + u32 total_size, size_left; + u32 part, part_offset; + u32 rc, v[2]; + void *devp = NULL, *pp = NULL; + char part_node[MTD_PART_NODE_LEN]; + + devp = finddevice("/mv64x60/flash"); + if (devp == NULL) { + printf("Missing flash device tree node\n\r"); + return; + } + + /* + * Get fist flash size: bank0, bank1 and total + */ + flash0_size = mv64x60_get_devcs_size(bridge_base, 0); + if (flash0_size == 0) + return; + + flash1_size = mv64x60_get_devcs_size(bridge_base, 1); + total_size = flash0_size + flash1_size; + + /* + * Set total flash size + */ + rc = getprop(devp, "reg", v, sizeof(v)); + if (rc != sizeof(v)) + fatal("Error: Can't find /mv64x60/flash/reg property\n\r"); + v[1] = total_size; + setprop(devp, "reg", v, sizeof(v)); + + /* + * Set Primary FS partition size: up to the end of first flash bank + */ + pp = find_node_by_prop_value_str(NULL, "label", "Primary FS"); + if (pp == NULL) + fatal("Error: Missing flash Primary FS device tree node\n\r"); + + rc = getprop(pp, "reg", v, sizeof(v)); + if (rc != sizeof(v)) + fatal("Error: Can't find /mv64x60/flash/[EMAIL PROTECTED] " + "property\n\r"); + + v[1] = flash0_size - MTD_PART_MONITOR_SIZE - MTD_PART_KERNEL_SIZE; + setprop(pp, "reg", v, sizeof(v)); + + if (flash1_size == 0) + /* Only 1 flash bank is presented */ + return; + + /* + * Ok, there is a second flash bank. Let's split it to partitions. + */ + + part_offset = flash0_size; + size_left = flash1_size; + + /* Skip Secondary Monitor if Boot Failover mechanism is disabled */ + rc = in_8(cpld_base + KATANAQP_CPLD_JSR) & KATANAQP_CPLD_JSR_EBFM; + part = rc ? 0 : 1; + + for (; part < MTD_PART_NUM; part++) { + + sprintf(part_node, "[EMAIL PROTECTED]", MTD_PART_NODE, part_offset); + pp = create_node(devp, part_node); + if (pp == NULL) + fatal("Error: Can't create new partition node\n\r"); + + setprop_str(pp, "label", katanaqp_mtd_parts[part].name); + + if (katanaqp_mtd_parts[part].ro) + setprop(pp, "read-only", NULL, 0); + + v[0] = part_offset; + v[1] = katanaqp_mtd_parts[part].size; + if (v[1] == 0) + /* Take all remaining space */ + v[1] = size_left; + + part_offset += v[1]; + size_left -= v[1]; + + setprop(pp, "reg", v, sizeof(v)); + + } +} + +static void katanaqp_fixups(void) +{ + u32 l, p, pnum; + void *devp = NULL; + struct katanaqp_board_info katanaqp_bif; + char model[BOARD_MODEL_LEN]; + + /* Check Katana Qp configuration */ + katanaqp_get_cfg(); + if (katanaqp_cfg == KATANAQP_CFG_UNKNOWN) + fatal("Error: Unsupported Katana Qp board configuration\n\r"); + + if (katanaqp_cfg == KATANAQP_CFG_PT5CC_CUSTOM) { + printf("Katana Qp board custom configuration detected, " + "using device tree defaults. Please, supply a correct " + "device tree\n\r"); + return; + } + + katanaqp_bif = katanaqp_board_info[katanaqp_cfg]; + + /* + * Set /model appropriately + */ + devp = finddevice("/"); + if (devp == NULL) + fatal("Error: Missing '/' device tree node\n\r"); + + /* + * Fix Board model name in device tree + */ + memset(model, 0, BOARD_MODEL_LEN); + + strncpy(model, BOARD_MODEL, BOARD_MODEL_MAX - 1); + l = strlen(model); + model[l++] = ' '; + + strncpy(&model[l], katanaqp_bif.cfg_name, BOARD_CFG_MAX - 1); + l += strlen(&model[l]); + model[l++] = '\0'; + + setprop(devp, "model", model, l); + + /* + * Do necessary bridge setup if we are monarch + */ + if (katanaqp_is_monarch()) + katanaqp_bridge_setup(); + + /* + * Fix RAM size and setup MV64460 bridge + */ + dt_fixup_memory(bd.bi_memstart, bd.bi_memsize); + + /* + * Fix flash size and partition layout + */ + katanaqp_flash_fixup(); + + /* + * Fix clocks + */ + dt_fixup_cpu_clocks(bd.bi_intfreq, bd.bi_busfreq / 4, bd.bi_busfreq); + + /* + * Fix phy addresses + */ + while ((devp = find_node_by_prop_value_str(devp, "comaptible", + "marvell,mv88e1111"))) { + getprop(devp, "block-index", &p, sizeof(p)); + pnum = katanaqp_bif.eth_phys[p]; + setprop_val(devp, "reg", pnum); + } +} + +static void katanaqp_reset(void) +{ + + /* issue hard reset to the reset command register */ + if (cpld_base) + out_8(cpld_base + KATANAQP_CPLD_RCR, + KATANAQP_CPLD_RCR_CPUHR); + + for (;;) ; +} + +void platform_init(unsigned long r3, unsigned long r4, unsigned long r5, + unsigned long r6, unsigned long r7) +{ + + CUBOOT_INIT(); + + if (ft_init(_dtb_start, _dtb_end - _dtb_start, 16)) + exit(); + + bridge_base = mv64x60_get_bridge_base(); + cpld_base = katanaqp_get_cpld_base(); + + platform_ops.fixups = katanaqp_fixups; + platform_ops.exit = katanaqp_reset; + + if (serial_console_init() < 0) + exit(); +} _______________________________________________ Linuxppc-dev mailing list Linuxppc-dev@ozlabs.org https://ozlabs.org/mailman/listinfo/linuxppc-dev