/* * derived from mol/mol.c, * Copyright (C) 2003, 2004 Samuel Rydh (samuel@ibrium.se) * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License * version 2 * */ #include "config.h" #include "arch/common/nvram.h" #include "packages/nvram.h" #include "libopenbios/bindings.h" #include "libc/byteorder.h" #include "libc/vsprintf.h" #include "drivers/drivers.h" #include "macio.h" #include "cuda.h" #include "pmu.h" #include "escc.h" #include "drivers/pci.h" #define OW_IO_NVRAM_SIZE 0x00020000 #define OW_IO_NVRAM_OFFSET 0x00060000 #define OW_IO_NVRAM_SHIFT 4 #define NW_IO_NVRAM_SIZE 0x00004000 #define NW_IO_NVRAM_OFFSET 0xfff04000 #define IO_OPENPIC_SIZE 0x00040000 #define IO_OPENPIC_OFFSET 0x00040000 static char *nvram; static int macio_nvram_shift(void) { int nvram_flat; if (is_oldworld()) return OW_IO_NVRAM_SHIFT; nvram_flat = fw_cfg_read_i32(FW_CFG_PPC_NVRAM_FLAT); return nvram_flat ? 0 : 1; } int macio_get_nvram_size(void) { int shift = macio_nvram_shift(); if (is_oldworld()) return OW_IO_NVRAM_SIZE >> shift; else return NW_IO_NVRAM_SIZE >> shift; } static unsigned long macio_nvram_offset(void) { unsigned long r; /* Hypervisor tells us where NVRAM lies */ r = fw_cfg_read_i32(FW_CFG_PPC_NVRAM_ADDR); if (r) return r; /* Fall back to hardcoded addresses */ if (is_oldworld()) return OW_IO_NVRAM_OFFSET; return NW_IO_NVRAM_OFFSET; } static unsigned long macio_nvram_size(void) { if (is_oldworld()) return OW_IO_NVRAM_SIZE; else return NW_IO_NVRAM_SIZE; } void macio_nvram_init(const char *path, phys_addr_t addr) { phandle_t chosen, aliases; phandle_t dnode; int props[2]; char buf[64]; unsigned long nvram_size, nvram_offset; nvram_offset = macio_nvram_offset(); nvram_size = macio_nvram_size(); nvram = (char*)addr + nvram_offset; nvconf_init(); snprintf(buf, sizeof(buf), "%s", path); dnode = nvram_init(buf); set_int_property(dnode, "#bytes", arch_nvram_size() ); props[0] = __cpu_to_be32(nvram_offset); props[1] = __cpu_to_be32(nvram_size); set_property(dnode, "reg", (char *)&props, sizeof(props)); set_property(dnode, "device_type", "nvram", 6); NEWWORLD(set_property(dnode, "compatible", "nvram,flash", 12)); chosen = find_dev("/chosen"); snprintf(buf, sizeof(buf), "%s", get_path_from_ph(dnode)); push_str(buf); fword("open-dev"); set_int_property(chosen, "nvram", POP()); aliases = find_dev("/aliases"); set_property(aliases, "nvram", buf, strlen(buf) + 1); } #ifdef DUMP_NVRAM static void dump_nvram(void) { int i, j; for (i = 0; i < 10; i++) { for (j = 0; j < 16; j++) printk ("%02x ", nvram[(i*16+j)<<4]); printk (" "); for (j = 0; j < 16; j++) if (isprint(nvram[(i*16+j)<<4])) printk("%c", nvram[(i*16+j)<<4]); else printk("."); printk ("\n"); } } #endif void macio_nvram_put(char *buf) { int i; unsigned int it_shift = macio_nvram_shift(); for (i=0; i < arch_nvram_size(); i++) nvram[i << it_shift] = buf[i]; #ifdef DUMP_NVRAM printk("new nvram:\n"); dump_nvram(); #endif } void macio_nvram_get(char *buf) { int i; unsigned int it_shift = macio_nvram_shift(); for (i=0; i< arch_nvram_size(); i++) buf[i] = nvram[i << it_shift]; #ifdef DUMP_NVRAM printk("current nvram:\n"); dump_nvram(); #endif } static void openpic_init(const char *path, phys_addr_t addr) { phandle_t dnode; int props[2]; char buf[128]; fword("new-device"); push_str("interrupt-controller"); fword("device-name"); snprintf(buf, sizeof(buf), "%s/interrupt-controller", path); dnode = find_dev(buf); set_property(dnode, "device_type", "open-pic", 9); set_property(dnode, "compatible", "chrp,open-pic", 14); set_property(dnode, "built-in", "", 0); props[0] = __cpu_to_be32(IO_OPENPIC_OFFSET); props[1] = __cpu_to_be32(IO_OPENPIC_SIZE); set_property(dnode, "reg", (char *)&props, sizeof(props)); set_int_property(dnode, "#interrupt-cells", 2); set_int_property(dnode, "#address-cells", 0); set_property(dnode, "interrupt-controller", "", 0); set_int_property(dnode, "clock-frequency", 4166666); fword("finish-device"); } DECLARE_UNNAMED_NODE(ob_macio, 0, sizeof(int)); /* ( str len -- addr ) */ static void ob_macio_decode_unit(void *private) { ucell addr; const char *arg = pop_fstr_copy(); addr = strtol(arg, NULL, 16); free((char*)arg); PUSH(addr); } /* ( addr -- str len ) */ static void ob_macio_encode_unit(void *private) { char buf[8]; ucell addr = POP(); snprintf(buf, sizeof(buf), "%x", addr); push_str(buf); } static void ob_macio_dma_alloc(int *idx) { call_parent_method("dma-alloc"); } static void ob_macio_dma_free(int *idx) { call_parent_method("dma-free"); } static void ob_macio_dma_map_in(int *idx) { call_parent_method("dma-map-in"); } static void ob_macio_dma_map_out(int *idx) { call_parent_method("dma-map-out"); } static void ob_macio_dma_sync(int *idx) { call_parent_method("dma-sync"); } NODE_METHODS(ob_macio) = { { "decode-unit", ob_macio_decode_unit }, { "encode-unit", ob_macio_encode_unit }, { "dma-alloc", ob_macio_dma_alloc }, { "dma-free", ob_macio_dma_free }, { "dma-map-in", ob_macio_dma_map_in }, { "dma-map-out", ob_macio_dma_map_out }, { "dma-sync", ob_macio_dma_sync }, }; void ob_unin_init(void) { phandle_t dnode; int props[2]; fword("new-device"); push_str("uni-n"); fword("device-name"); dnode = find_dev("/uni-n"); set_property(dnode, "device_type", "memory-controller", 18); set_property(dnode, "compatible", "uni-north", 10); set_int_property(dnode, "device-rev", 7); props[0] = __cpu_to_be32(0xf8000000); props[1] = __cpu_to_be32(0x1000000); set_property(dnode, "reg", (char *)&props, sizeof(props)); fword("finish-device"); } static void macio_gpio_init(const char *path) { fword("new-device"); push_str("gpio"); fword("device-name"); push_str("gpio"); fword("device-type"); PUSH(1); fword("encode-int"); push_str("#address-cells"); fword("property"); PUSH(0); fword("encode-int"); push_str("#size-cells"); fword("property"); push_str("mac-io-gpio"); fword("encode-string"); push_str("compatible"); fword("property"); PUSH(0x50); fword("encode-int"); PUSH(0x30); fword("encode-int"); fword("encode+"); push_str("reg"); fword("property"); /* Build the extint-gpio1 for the PMU */ fword("new-device"); push_str("extint-gpio1"); fword("device-name"); PUSH(0x2f); fword("encode-int"); PUSH(0x1); fword("encode-int"); fword("encode+"); push_str("interrupts"); fword("property"); PUSH(0x9); fword("encode-int"); push_str("reg"); fword("property"); push_str("keywest-gpio1"); fword("encode-string"); push_str("gpio"); fword("encode-string"); fword("encode+"); push_str("compatible"); fword("property"); fword("finish-device"); /* Build the programmer-switch */ fword("new-device"); push_str("programmer-switch"); fword("device-name"); push_str("programmer-switch"); fword("encode-string"); push_str("device_type"); fword("property"); PUSH(0x37); fword("encode-int"); PUSH(0x0); fword("encode-int"); fword("encode+"); push_str("interrupts"); fword("property"); fword("finish-device"); fword("finish-device"); } void ob_macio_heathrow_init(const char *path, phys_addr_t addr) { phandle_t aliases; BIND_NODE_METHODS(get_cur_dev(), ob_macio); cuda_init(path, addr); macio_nvram_init(path, addr); escc_init(path, addr); macio_ide_init(path, addr, 2); aliases = find_dev("/aliases"); set_property(aliases, "mac-io", path, strlen(path) + 1); } void ob_macio_keylargo_init(const char *path, phys_addr_t addr) { phandle_t aliases; BIND_NODE_METHODS(get_cur_dev(), ob_macio); if (has_pmu()) { macio_gpio_init(path); pmu_init(path, addr); } else { cuda_init(path, addr); } escc_init(path, addr); macio_ide_init(path, addr, 2); openpic_init(path, addr); aliases = find_dev("/aliases"); set_property(aliases, "mac-io", path, strlen(path) + 1); }