blob: 496bab13f67f29fcb397802a70962c4080fbb52f [file] [log] [blame]
/*
* 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);
}