/* * Copyright (C) 2013 Jean-Christophe PLAGNIOL-VILLARD * * GPLv2 only */ #include #include #include #include #include #include #include #include #include #include #include #include #include #define FIRMWARE_DTB_BASE 0x1000 #define HB_OPP_VERSION 0 struct fdt_header *fdt = NULL; static int hb_fixup(struct device_node *root, void *unused) { struct device_node *node; u32 reg = readl(sregs_base + HB_SREG_A9_PWRDOM_DATA); u32 *opp_table = (u32 *)HB_SYSRAM_OPP_TABLE_BASE; u32 dtb_table[2*10]; u32 i; u32 num_opps; __be32 latency; if (!(reg & HB_PWRDOM_STAT_SATA)) { for_each_compatible_node(node, NULL, "calxeda,hb-ahci") of_set_property(node, "status", "disabled", sizeof("disabled"), 1); } if (!(reg & HB_PWRDOM_STAT_EMMC)) { for_each_compatible_node(node, NULL, "calxeda,hb-sdhci") of_set_property(node, "status", "disabled", sizeof("disabled"), 1); } if ((opp_table[0] >> 16) != HB_OPP_VERSION) return 0; node = of_find_node_by_path("/cpus/cpu@0"); if (!node) return 0; num_opps = opp_table[0] & 0xff; for (i = 0; i < num_opps; i++) { dtb_table[2 * i] = cpu_to_be32(opp_table[3 + 3 * i]); dtb_table[2 * i + 1] = cpu_to_be32(opp_table[2 + 3 * i]); } latency = cpu_to_be32(opp_table[1]); of_set_property(node, "transition-latency", &latency, 4, 1); of_set_property(node, "operating-points", dtb_table, 8 * num_opps, 1); return 0; } static int highbank_mem_init(void) { struct device_node *root, *np; int ret; /* load by the firmware at 0x1000 */ fdt = IOMEM(FIRMWARE_DTB_BASE); root = of_unflatten_dtb(fdt); if (!root) { pr_warn("no dtb found at 0x1000 use default configuration\n"); fdt = NULL; goto not_found; } of_set_root_node(root); np = of_find_node_by_path("/memory"); if (!np) { pr_warn("no memory node use default configuration\n"); goto not_found; } ret = of_add_memory(np, true); if (ret) { pr_warn("memory node: probe failed use default configuration\n"); goto not_found; } pr_info("highbank: dtb probed memory size\n"); return 0; not_found: highbank_add_ddram(4089 << 20); return 0; } mem_initcall(highbank_mem_init); static int highbank_devices_init(void) { of_register_fixup(hb_fixup, NULL); if (!fdt) { highbank_register_gpio(0); highbank_register_gpio(1); highbank_register_gpio(2); highbank_register_gpio(3); highbank_register_ahci(); highbank_register_xgmac(0); highbank_register_xgmac(1); } else { fdt = of_get_fixed_tree(NULL); add_mem_device("dtb", (unsigned long)fdt, be32_to_cpu(fdt->totalsize), IORESOURCE_MEM_WRITEABLE); devfs_add_partition("ram0", FIRMWARE_DTB_BASE, SZ_64K, DEVFS_PARTITION_FIXED, "firmware-dtb"); } devfs_add_partition("nvram", 0x00000, SZ_16K, DEVFS_PARTITION_FIXED, "env0"); return 0; } device_initcall(highbank_devices_init); static int highbank_console_init(void) { barebox_set_model("Calxeda Highbank"); barebox_set_hostname("highbank"); highbank_register_uart(); return 0; } console_initcall(highbank_console_init);