Subversion Repositories HelenOS

Compare Revisions

Ignore whitespace Rev 3342 → Rev 3343

/branches/sparc/kernel/arch/sparc64/src/drivers/scr.c
0,0 → 1,182
/*
* Copyright (c) 2006 Jakub Jermar
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
*
* - Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* - Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* - The name of the author may not be used to endorse or promote products
* derived from this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
* IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
* OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
* IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
* NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
* THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
 
/** @addtogroup sparc64
* @{
*/
/** @file
*/
 
#include <arch/drivers/scr.h>
#include <genarch/ofw/ofw_tree.h>
#include <genarch/fb/fb.h>
#include <genarch/fb/visuals.h>
#include <arch/types.h>
#include <func.h>
#include <align.h>
#include <print.h>
 
#define FFB_REG_24BPP 7
 
scr_type_t scr_type = SCR_UNKNOWN;
 
/** Initialize screen.
*
* Traverse OpenFirmware device tree in order to find necessary
* info about the screen device.
*
* @param node Screen device node.
*/
void scr_init(ofw_tree_node_t *node)
{
ofw_tree_property_t *prop;
const char *name;
name = ofw_tree_node_name(node);
if (strcmp(name, "SUNW,m64B") == 0)
scr_type = SCR_ATYFB;
else if (strcmp(name, "SUNW,ffb") == 0)
scr_type = SCR_FFB;
else if (strcmp(name, "cgsix") == 0)
scr_type = SCR_CGSIX;
if (scr_type == SCR_UNKNOWN) {
printf("Unknown keyboard device.\n");
return;
}
uintptr_t fb_addr;
uint32_t fb_width = 0;
uint32_t fb_height = 0;
uint32_t fb_depth = 0;
uint32_t fb_linebytes = 0;
uint32_t fb_scanline = 0;
unsigned int visual;
 
prop = ofw_tree_getprop(node, "width");
if (prop && prop->value)
fb_width = *((uint32_t *) prop->value);
 
prop = ofw_tree_getprop(node, "height");
if (prop && prop->value)
fb_height = *((uint32_t *) prop->value);
 
prop = ofw_tree_getprop(node, "depth");
if (prop && prop->value)
fb_depth = *((uint32_t *) prop->value);
 
prop = ofw_tree_getprop(node, "linebytes");
if (prop && prop->value)
fb_linebytes = *((uint32_t *) prop->value);
 
prop = ofw_tree_getprop(node, "reg");
if (!prop)
panic("Can't find \"reg\" property.\n");
 
switch (scr_type) {
case SCR_ATYFB:
if (prop->size / sizeof(ofw_pci_reg_t) < 2) {
printf("Too few screen registers.\n");
return;
}
ofw_pci_reg_t *fb_reg = &((ofw_pci_reg_t *) prop->value)[1];
ofw_pci_reg_t abs_reg;
if (!ofw_pci_reg_absolutize(node, fb_reg, &abs_reg)) {
printf("Failed to absolutize fb register.\n");
return;
}
if (!ofw_pci_apply_ranges(node->parent, &abs_reg , &fb_addr)) {
printf("Failed to determine screen address.\n");
return;
}
switch (fb_depth) {
case 8:
fb_scanline = fb_linebytes * (fb_depth >> 3);
visual = VISUAL_INDIRECT_8;
break;
case 16:
fb_scanline = fb_linebytes * (fb_depth >> 3);
visual = VISUAL_RGB_5_6_5;
break;
case 24:
fb_scanline = fb_linebytes * 4;
visual = VISUAL_RGB_8_8_8_0;
break;
case 32:
fb_scanline = fb_linebytes * (fb_depth >> 3);
visual = VISUAL_RGB_0_8_8_8;
break;
default:
printf("Unsupported bits per pixel.\n");
return;
}
break;
case SCR_FFB:
fb_scanline = 8192;
visual = VISUAL_BGR_0_8_8_8;
 
ofw_upa_reg_t *reg = &((ofw_upa_reg_t *) prop->value)[FFB_REG_24BPP];
if (!ofw_upa_apply_ranges(node->parent, reg, &fb_addr)) {
printf("Failed to determine screen address.\n");
return;
}
 
break;
case SCR_CGSIX:
switch (fb_depth) {
case 8:
fb_scanline = fb_linebytes;
visual = VISUAL_INDIRECT_8;
break;
default:
printf("Not implemented.\n");
return;
}
ofw_sbus_reg_t *cg6_reg = &((ofw_sbus_reg_t *) prop->value)[0];
if (!ofw_sbus_apply_ranges(node->parent, cg6_reg, &fb_addr)) {
printf("Failed to determine screen address.\n");
return;
}
break;
default:
panic("Unexpected type.\n");
}
 
fb_init(fb_addr, fb_width, fb_height, fb_scanline, visual);
}
 
/** @}
*/
/branches/sparc/kernel/arch/sparc64/src/drivers/tick.c
0,0 → 1,109
/*
* Copyright (c) 2005 Jakub Jermar
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
*
* - Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* - Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* - The name of the author may not be used to endorse or promote products
* derived from this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
* IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
* OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
* IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
* NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
* THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
 
/** @addtogroup sparc64
* @{
*/
/** @file
*/
 
#include <arch/drivers/tick.h>
#include <arch/interrupt.h>
#include <arch/sparc64.h>
#include <arch/asm.h>
#include <arch/register.h>
#include <arch/cpu.h>
#include <arch/boot/boot.h>
#include <time/clock.h>
#include <arch.h>
#include <debug.h>
 
#define TICK_RESTART_TIME 50 /* Worst case estimate. */
 
/** Initialize tick interrupt. */
void tick_init(void)
{
tick_compare_reg_t compare;
interrupt_register(14, "tick_int", tick_interrupt);
compare.int_dis = false;
compare.tick_cmpr = CPU->arch.clock_frequency / HZ;
CPU->arch.next_tick_cmpr = compare.tick_cmpr;
tick_compare_write(compare.value);
tick_write(0);
}
 
/** Process tick interrupt.
*
* @param n Interrupt Level, 14, (can be ignored)
* @param istate Interrupted state.
*/
void tick_interrupt(int n, istate_t *istate)
{
softint_reg_t softint, clear;
uint64_t drift;
softint.value = softint_read();
/*
* Make sure we are servicing interrupt_level_14
*/
ASSERT(n == 14);
/*
* Make sure we are servicing TICK_INT.
*/
ASSERT(softint.tick_int);
 
/*
* Clear tick interrupt.
*/
clear.value = 0;
clear.tick_int = 1;
clear_softint_write(clear.value);
/*
* Reprogram the compare register.
* For now, we can ignore the potential of the registers to overflow.
* On a 360MHz Ultra 60, the 63-bit compare counter will overflow in
* about 812 years. If there was a 2GHz UltraSPARC computer, it would
* overflow only in 146 years.
*/
drift = tick_read() - CPU->arch.next_tick_cmpr;
while (drift > CPU->arch.clock_frequency / HZ) {
drift -= CPU->arch.clock_frequency / HZ;
CPU->missed_clock_ticks++;
}
CPU->arch.next_tick_cmpr = tick_read() +
(CPU->arch.clock_frequency / HZ) - drift;
tick_compare_write(CPU->arch.next_tick_cmpr);
clock();
}
 
/** @}
*/
/branches/sparc/kernel/arch/sparc64/src/drivers/fhc.c
0,0 → 1,119
/*
* Copyright (c) 2006 Jakub Jermar
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
*
* - Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* - Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* - The name of the author may not be used to endorse or promote products
* derived from this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
* IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
* OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
* IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
* NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
* THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
 
/** @addtogroup sparc64
* @{
*/
/**
* @file
* @brief FireHose Controller (FHC) driver.
*
* Note that this driver is a result of reverse engineering
* rather than implementation of a specification. This
* is due to the fact that the FHC documentation is not
* publicly available.
*/
 
#include <arch/drivers/fhc.h>
#include <arch/trap/interrupt.h>
#include <mm/page.h>
#include <mm/slab.h>
#include <arch/types.h>
#include <genarch/ofw/ofw_tree.h>
 
fhc_t *central_fhc = NULL;
 
/**
* I suspect this must be hardcoded in the FHC.
* If it is not, than we can read all IMAP registers
* and get the complete mapping.
*/
#define FHC_UART_INR 0x39
 
#define FHC_UART_IMAP 0x0
#define FHC_UART_ICLR 0x4
 
#define UART_IMAP_REG 4
 
fhc_t *fhc_init(ofw_tree_node_t *node)
{
fhc_t *fhc;
ofw_tree_property_t *prop;
 
prop = ofw_tree_getprop(node, "reg");
if (!prop || !prop->value)
return NULL;
count_t regs = prop->size / sizeof(ofw_central_reg_t);
if (regs + 1 < UART_IMAP_REG)
return NULL;
 
ofw_central_reg_t *reg = &((ofw_central_reg_t *) prop->value)[UART_IMAP_REG];
 
uintptr_t paddr;
if (!ofw_central_apply_ranges(node->parent, reg, &paddr))
return NULL;
 
fhc = (fhc_t *) malloc(sizeof(fhc_t), FRAME_ATOMIC);
if (!fhc)
return NULL;
 
fhc->uart_imap = (uint32_t *) hw_map(paddr, reg->size);
return fhc;
}
 
void fhc_enable_interrupt(fhc_t *fhc, int inr)
{
switch (inr) {
case FHC_UART_INR:
fhc->uart_imap[FHC_UART_IMAP] |= IMAP_V_MASK;
break;
default:
panic("Unexpected INR (%d)\n", inr);
break;
}
}
 
void fhc_clear_interrupt(fhc_t *fhc, int inr)
{
ASSERT(fhc->uart_imap);
 
switch (inr) {
case FHC_UART_INR:
fhc->uart_imap[FHC_UART_ICLR] = 0;
break;
default:
panic("Unexpected INR (%d)\n", inr);
break;
}
}
 
/** @}
*/
/branches/sparc/kernel/arch/sparc64/src/drivers/kbd.c
0,0 → 1,159
/*
* Copyright (c) 2006 Jakub Jermar
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
*
* - Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* - Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* - The name of the author may not be used to endorse or promote products
* derived from this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
* IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
* OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
* IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
* NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
* THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
 
/** @addtogroup sparc64
* @{
*/
/** @file
*/
 
#include <arch/drivers/kbd.h>
#include <genarch/ofw/ofw_tree.h>
#ifdef CONFIG_Z8530
#include <genarch/kbd/z8530.h>
#endif
#ifdef CONFIG_NS16550
#include <genarch/kbd/ns16550.h>
#endif
#include <ddi/device.h>
#include <ddi/irq.h>
#include <arch/mm/page.h>
#include <arch/types.h>
#include <align.h>
#include <func.h>
#include <print.h>
 
kbd_type_t kbd_type = KBD_UNKNOWN;
 
/** Initialize keyboard.
*
* Traverse OpenFirmware device tree in order to find necessary
* info about the keyboard device.
*
* @param node Keyboard device node.
*/
void kbd_init(ofw_tree_node_t *node)
{
size_t offset;
uintptr_t aligned_addr;
ofw_tree_property_t *prop;
const char *name;
name = ofw_tree_node_name(node);
/*
* Determine keyboard serial controller type.
*/
if (strcmp(name, "zs") == 0)
kbd_type = KBD_Z8530;
else if (strcmp(name, "su") == 0)
kbd_type = KBD_NS16550;
if (kbd_type == KBD_UNKNOWN) {
printf("Unknown keyboard device.\n");
return;
}
/*
* Read 'interrupts' property.
*/
uint32_t interrupts;
prop = ofw_tree_getprop(node, "interrupts");
if (!prop || !prop->value)
panic("Can't find \"interrupts\" property.\n");
interrupts = *((uint32_t *) prop->value);
 
/*
* Read 'reg' property.
*/
prop = ofw_tree_getprop(node, "reg");
if (!prop || !prop->value)
panic("Can't find \"reg\" property.\n");
uintptr_t pa;
size_t size;
inr_t inr;
devno_t devno = device_assign_devno();
switch (kbd_type) {
case KBD_Z8530:
size = ((ofw_fhc_reg_t *) prop->value)->size;
if (!ofw_fhc_apply_ranges(node->parent, ((ofw_fhc_reg_t *) prop->value) , &pa)) {
printf("Failed to determine keyboard address.\n");
return;
}
if (!ofw_fhc_map_interrupt(node->parent, ((ofw_fhc_reg_t *) prop->value), interrupts, &inr)) {
printf("Failed to determine keyboard interrupt.\n");
return;
}
break;
case KBD_NS16550:
size = ((ofw_ebus_reg_t *) prop->value)->size;
if (!ofw_ebus_apply_ranges(node->parent, ((ofw_ebus_reg_t *) prop->value) , &pa)) {
printf("Failed to determine keyboard address.\n");
return;
}
if (!ofw_ebus_map_interrupt(node->parent, ((ofw_ebus_reg_t *) prop->value), interrupts, &inr)) {
printf("Failed to determine keyboard interrupt.\n");
return;
};
break;
 
default:
panic("Unexpected type.\n");
}
/*
* We need to pass aligned address to hw_map().
* However, the physical keyboard address can
* be pretty much unaligned, depending on the
* underlying controller.
*/
aligned_addr = ALIGN_DOWN(pa, PAGE_SIZE);
offset = pa - aligned_addr;
uintptr_t vaddr = hw_map(aligned_addr, offset + size) + offset;
 
switch (kbd_type) {
#ifdef CONFIG_Z8530
case KBD_Z8530:
z8530_init(devno, inr, vaddr);
break;
#endif
#ifdef CONFIG_NS16550
case KBD_NS16550:
ns16550_init(devno, inr, vaddr);
break;
#endif
default:
printf("Kernel is not compiled with the necessary keyboard driver this machine requires.\n");
}
}
 
/** @}
*/
/branches/sparc/kernel/arch/sparc64/src/drivers/pci.c
0,0 → 1,231
/*
* Copyright (c) 2006 Jakub Jermar
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
*
* - Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* - Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* - The name of the author may not be used to endorse or promote products
* derived from this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
* IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
* OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
* IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
* NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
* THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
 
/** @addtogroup sparc64
* @{
*/
/**
* @file
* @brief PCI driver.
*/
 
#include <arch/drivers/pci.h>
#include <genarch/ofw/ofw_tree.h>
#include <arch/trap/interrupt.h>
#include <mm/page.h>
#include <mm/slab.h>
#include <arch/types.h>
#include <debug.h>
#include <print.h>
#include <func.h>
#include <arch/asm.h>
 
#define PCI_SABRE_REGS_REG 0
 
#define PCI_SABRE_IMAP_BASE 0x200
#define PCI_SABRE_ICLR_BASE 0x300
 
#define PCI_PSYCHO_REGS_REG 2
 
#define PCI_PSYCHO_IMAP_BASE 0x200
#define PCI_PSYCHO_ICLR_BASE 0x300
 
static pci_t *pci_sabre_init(ofw_tree_node_t *node);
static void pci_sabre_enable_interrupt(pci_t *pci, int inr);
static void pci_sabre_clear_interrupt(pci_t *pci, int inr);
 
static pci_t *pci_psycho_init(ofw_tree_node_t *node);
static void pci_psycho_enable_interrupt(pci_t *pci, int inr);
static void pci_psycho_clear_interrupt(pci_t *pci, int inr);
 
/** PCI operations for Sabre model. */
static pci_operations_t pci_sabre_ops = {
.enable_interrupt = pci_sabre_enable_interrupt,
.clear_interrupt = pci_sabre_clear_interrupt
};
/** PCI operations for Psycho model. */
static pci_operations_t pci_psycho_ops = {
.enable_interrupt = pci_psycho_enable_interrupt,
.clear_interrupt = pci_psycho_clear_interrupt
};
 
/** Initialize PCI controller (model Sabre).
*
* @param node OpenFirmware device tree node of the Sabre.
*
* @return Address of the initialized PCI structure.
*/
pci_t *pci_sabre_init(ofw_tree_node_t *node)
{
pci_t *pci;
ofw_tree_property_t *prop;
 
/*
* Get registers.
*/
prop = ofw_tree_getprop(node, "reg");
if (!prop || !prop->value)
return NULL;
 
ofw_upa_reg_t *reg = prop->value;
count_t regs = prop->size / sizeof(ofw_upa_reg_t);
 
if (regs < PCI_SABRE_REGS_REG + 1)
return NULL;
 
uintptr_t paddr;
if (!ofw_upa_apply_ranges(node->parent, &reg[PCI_SABRE_REGS_REG], &paddr))
return NULL;
 
pci = (pci_t *) malloc(sizeof(pci_t), FRAME_ATOMIC);
if (!pci)
return NULL;
 
pci->model = PCI_SABRE;
pci->op = &pci_sabre_ops;
pci->reg = (uint64_t *) hw_map(paddr, reg[PCI_SABRE_REGS_REG].size);
 
return pci;
}
 
 
/** Initialize the Psycho PCI controller.
*
* @param node OpenFirmware device tree node of the Psycho.
*
* @return Address of the initialized PCI structure.
*/
pci_t *pci_psycho_init(ofw_tree_node_t *node)
{
pci_t *pci;
ofw_tree_property_t *prop;
 
/*
* Get registers.
*/
prop = ofw_tree_getprop(node, "reg");
if (!prop || !prop->value)
return NULL;
 
ofw_upa_reg_t *reg = prop->value;
count_t regs = prop->size / sizeof(ofw_upa_reg_t);
 
if (regs < PCI_PSYCHO_REGS_REG + 1)
return NULL;
 
uintptr_t paddr;
if (!ofw_upa_apply_ranges(node->parent, &reg[PCI_PSYCHO_REGS_REG], &paddr))
return NULL;
 
pci = (pci_t *) malloc(sizeof(pci_t), FRAME_ATOMIC);
if (!pci)
return NULL;
 
pci->model = PCI_PSYCHO;
pci->op = &pci_psycho_ops;
pci->reg = (uint64_t *) hw_map(paddr, reg[PCI_PSYCHO_REGS_REG].size);
 
return pci;
}
 
void pci_sabre_enable_interrupt(pci_t *pci, int inr)
{
pci->reg[PCI_SABRE_IMAP_BASE + (inr & INO_MASK)] |= IMAP_V_MASK;
}
 
void pci_sabre_clear_interrupt(pci_t *pci, int inr)
{
pci->reg[PCI_SABRE_ICLR_BASE + (inr & INO_MASK)] = 0;
}
 
void pci_psycho_enable_interrupt(pci_t *pci, int inr)
{
pci->reg[PCI_PSYCHO_IMAP_BASE + (inr & INO_MASK)] |= IMAP_V_MASK;
}
 
void pci_psycho_clear_interrupt(pci_t *pci, int inr)
{
pci->reg[PCI_PSYCHO_ICLR_BASE + (inr & INO_MASK)] = 0;
}
 
/** Initialize PCI controller. */
pci_t *pci_init(ofw_tree_node_t *node)
{
ofw_tree_property_t *prop;
 
/*
* First, verify this is a PCI node.
*/
ASSERT(strcmp(ofw_tree_node_name(node), "pci") == 0);
 
/*
* Determine PCI controller model.
*/
prop = ofw_tree_getprop(node, "model");
if (!prop || !prop->value)
return NULL;
if (strcmp(prop->value, "SUNW,sabre") == 0) {
/*
* PCI controller Sabre.
* This model is found on UltraSPARC IIi based machines.
*/
return pci_sabre_init(node);
} else if (strcmp(prop->value, "SUNW,psycho") == 0) {
/*
* PCI controller Psycho.
* Used on UltraSPARC II based processors, for instance,
* on Ultra 60.
*/
return pci_psycho_init(node);
} else {
/*
* Unsupported model.
*/
printf("Unsupported PCI controller model (%s).\n", prop->value);
}
 
return NULL;
}
 
void pci_enable_interrupt(pci_t *pci, int inr)
{
ASSERT(pci->model);
ASSERT(pci->op && pci->op->enable_interrupt);
pci->op->enable_interrupt(pci, inr);
}
 
void pci_clear_interrupt(pci_t *pci, int inr)
{
ASSERT(pci->model);
ASSERT(pci->op && pci->op->clear_interrupt);
pci->op->clear_interrupt(pci, inr);
}
 
/** @}
*/