forked from Minki/linux
a88b5ba8bd
o Move all files from sparc64/kernel/ to sparc/kernel - rename as appropriate o Update sparc/Makefile to the changes o Update sparc/kernel/Makefile to include the sparc64 files NOTE: This commit changes link order on sparc64! Link order had to change for either of sparc32 and sparc64. And assuming sparc64 see more testing than sparc32 change link order on sparc64 where issues will be caught faster. Signed-off-by: Sam Ravnborg <sam@ravnborg.org> Signed-off-by: David S. Miller <davem@davemloft.net>
269 lines
6.0 KiB
C
269 lines
6.0 KiB
C
/* central.c: Central FHC driver for Sunfire/Starfire/Wildfire.
|
|
*
|
|
* Copyright (C) 1997, 1999, 2008 David S. Miller (davem@davemloft.net)
|
|
*/
|
|
|
|
#include <linux/kernel.h>
|
|
#include <linux/types.h>
|
|
#include <linux/string.h>
|
|
#include <linux/init.h>
|
|
#include <linux/of_device.h>
|
|
#include <linux/platform_device.h>
|
|
|
|
#include <asm/fhc.h>
|
|
#include <asm/upa.h>
|
|
|
|
struct clock_board {
|
|
void __iomem *clock_freq_regs;
|
|
void __iomem *clock_regs;
|
|
void __iomem *clock_ver_reg;
|
|
int num_slots;
|
|
struct resource leds_resource;
|
|
struct platform_device leds_pdev;
|
|
};
|
|
|
|
struct fhc {
|
|
void __iomem *pregs;
|
|
bool central;
|
|
bool jtag_master;
|
|
int board_num;
|
|
struct resource leds_resource;
|
|
struct platform_device leds_pdev;
|
|
};
|
|
|
|
static int __devinit clock_board_calc_nslots(struct clock_board *p)
|
|
{
|
|
u8 reg = upa_readb(p->clock_regs + CLOCK_STAT1) & 0xc0;
|
|
|
|
switch (reg) {
|
|
case 0x40:
|
|
return 16;
|
|
|
|
case 0xc0:
|
|
return 8;
|
|
|
|
case 0x80:
|
|
reg = 0;
|
|
if (p->clock_ver_reg)
|
|
reg = upa_readb(p->clock_ver_reg);
|
|
if (reg) {
|
|
if (reg & 0x80)
|
|
return 4;
|
|
else
|
|
return 5;
|
|
}
|
|
/* Fallthrough */
|
|
default:
|
|
return 4;
|
|
}
|
|
}
|
|
|
|
static int __devinit clock_board_probe(struct of_device *op,
|
|
const struct of_device_id *match)
|
|
{
|
|
struct clock_board *p = kzalloc(sizeof(*p), GFP_KERNEL);
|
|
int err = -ENOMEM;
|
|
|
|
if (!p) {
|
|
printk(KERN_ERR "clock_board: Cannot allocate struct clock_board\n");
|
|
goto out;
|
|
}
|
|
|
|
p->clock_freq_regs = of_ioremap(&op->resource[0], 0,
|
|
resource_size(&op->resource[0]),
|
|
"clock_board_freq");
|
|
if (!p->clock_freq_regs) {
|
|
printk(KERN_ERR "clock_board: Cannot map clock_freq_regs\n");
|
|
goto out_free;
|
|
}
|
|
|
|
p->clock_regs = of_ioremap(&op->resource[1], 0,
|
|
resource_size(&op->resource[1]),
|
|
"clock_board_regs");
|
|
if (!p->clock_regs) {
|
|
printk(KERN_ERR "clock_board: Cannot map clock_regs\n");
|
|
goto out_unmap_clock_freq_regs;
|
|
}
|
|
|
|
if (op->resource[2].flags) {
|
|
p->clock_ver_reg = of_ioremap(&op->resource[2], 0,
|
|
resource_size(&op->resource[2]),
|
|
"clock_ver_reg");
|
|
if (!p->clock_ver_reg) {
|
|
printk(KERN_ERR "clock_board: Cannot map clock_ver_reg\n");
|
|
goto out_unmap_clock_regs;
|
|
}
|
|
}
|
|
|
|
p->num_slots = clock_board_calc_nslots(p);
|
|
|
|
p->leds_resource.start = (unsigned long)
|
|
(p->clock_regs + CLOCK_CTRL);
|
|
p->leds_resource.end = p->leds_resource.end;
|
|
p->leds_resource.name = "leds";
|
|
|
|
p->leds_pdev.name = "sunfire-clockboard-leds";
|
|
p->leds_pdev.resource = &p->leds_resource;
|
|
p->leds_pdev.num_resources = 1;
|
|
p->leds_pdev.dev.parent = &op->dev;
|
|
|
|
err = platform_device_register(&p->leds_pdev);
|
|
if (err) {
|
|
printk(KERN_ERR "clock_board: Could not register LEDS "
|
|
"platform device\n");
|
|
goto out_unmap_clock_ver_reg;
|
|
}
|
|
|
|
printk(KERN_INFO "clock_board: Detected %d slot Enterprise system.\n",
|
|
p->num_slots);
|
|
|
|
err = 0;
|
|
out:
|
|
return err;
|
|
|
|
out_unmap_clock_ver_reg:
|
|
if (p->clock_ver_reg)
|
|
of_iounmap(&op->resource[2], p->clock_ver_reg,
|
|
resource_size(&op->resource[2]));
|
|
|
|
out_unmap_clock_regs:
|
|
of_iounmap(&op->resource[1], p->clock_regs,
|
|
resource_size(&op->resource[1]));
|
|
|
|
out_unmap_clock_freq_regs:
|
|
of_iounmap(&op->resource[0], p->clock_freq_regs,
|
|
resource_size(&op->resource[0]));
|
|
|
|
out_free:
|
|
kfree(p);
|
|
goto out;
|
|
}
|
|
|
|
static struct of_device_id __initdata clock_board_match[] = {
|
|
{
|
|
.name = "clock-board",
|
|
},
|
|
{},
|
|
};
|
|
|
|
static struct of_platform_driver clock_board_driver = {
|
|
.match_table = clock_board_match,
|
|
.probe = clock_board_probe,
|
|
.driver = {
|
|
.name = "clock_board",
|
|
},
|
|
};
|
|
|
|
static int __devinit fhc_probe(struct of_device *op,
|
|
const struct of_device_id *match)
|
|
{
|
|
struct fhc *p = kzalloc(sizeof(*p), GFP_KERNEL);
|
|
int err = -ENOMEM;
|
|
u32 reg;
|
|
|
|
if (!p) {
|
|
printk(KERN_ERR "fhc: Cannot allocate struct fhc\n");
|
|
goto out;
|
|
}
|
|
|
|
if (!strcmp(op->node->parent->name, "central"))
|
|
p->central = true;
|
|
|
|
p->pregs = of_ioremap(&op->resource[0], 0,
|
|
resource_size(&op->resource[0]),
|
|
"fhc_pregs");
|
|
if (!p->pregs) {
|
|
printk(KERN_ERR "fhc: Cannot map pregs\n");
|
|
goto out_free;
|
|
}
|
|
|
|
if (p->central) {
|
|
reg = upa_readl(p->pregs + FHC_PREGS_BSR);
|
|
p->board_num = ((reg >> 16) & 1) | ((reg >> 12) & 0x0e);
|
|
} else {
|
|
p->board_num = of_getintprop_default(op->node, "board#", -1);
|
|
if (p->board_num == -1) {
|
|
printk(KERN_ERR "fhc: No board# property\n");
|
|
goto out_unmap_pregs;
|
|
}
|
|
if (upa_readl(p->pregs + FHC_PREGS_JCTRL) & FHC_JTAG_CTRL_MENAB)
|
|
p->jtag_master = true;
|
|
}
|
|
|
|
if (!p->central) {
|
|
p->leds_resource.start = (unsigned long)
|
|
(p->pregs + FHC_PREGS_CTRL);
|
|
p->leds_resource.end = p->leds_resource.end;
|
|
p->leds_resource.name = "leds";
|
|
|
|
p->leds_pdev.name = "sunfire-fhc-leds";
|
|
p->leds_pdev.resource = &p->leds_resource;
|
|
p->leds_pdev.num_resources = 1;
|
|
p->leds_pdev.dev.parent = &op->dev;
|
|
|
|
err = platform_device_register(&p->leds_pdev);
|
|
if (err) {
|
|
printk(KERN_ERR "fhc: Could not register LEDS "
|
|
"platform device\n");
|
|
goto out_unmap_pregs;
|
|
}
|
|
}
|
|
reg = upa_readl(p->pregs + FHC_PREGS_CTRL);
|
|
|
|
if (!p->central)
|
|
reg |= FHC_CONTROL_IXIST;
|
|
|
|
reg &= ~(FHC_CONTROL_AOFF |
|
|
FHC_CONTROL_BOFF |
|
|
FHC_CONTROL_SLINE);
|
|
|
|
upa_writel(reg, p->pregs + FHC_PREGS_CTRL);
|
|
upa_readl(p->pregs + FHC_PREGS_CTRL);
|
|
|
|
reg = upa_readl(p->pregs + FHC_PREGS_ID);
|
|
printk(KERN_INFO "fhc: Board #%d, Version[%x] PartID[%x] Manuf[%x] %s\n",
|
|
p->board_num,
|
|
(reg & FHC_ID_VERS) >> 28,
|
|
(reg & FHC_ID_PARTID) >> 12,
|
|
(reg & FHC_ID_MANUF) >> 1,
|
|
(p->jtag_master ?
|
|
"(JTAG Master)" :
|
|
(p->central ? "(Central)" : "")));
|
|
|
|
err = 0;
|
|
|
|
out:
|
|
return err;
|
|
|
|
out_unmap_pregs:
|
|
of_iounmap(&op->resource[0], p->pregs, resource_size(&op->resource[0]));
|
|
|
|
out_free:
|
|
kfree(p);
|
|
goto out;
|
|
}
|
|
|
|
static struct of_device_id __initdata fhc_match[] = {
|
|
{
|
|
.name = "fhc",
|
|
},
|
|
{},
|
|
};
|
|
|
|
static struct of_platform_driver fhc_driver = {
|
|
.match_table = fhc_match,
|
|
.probe = fhc_probe,
|
|
.driver = {
|
|
.name = "fhc",
|
|
},
|
|
};
|
|
|
|
static int __init sunfire_init(void)
|
|
{
|
|
(void) of_register_driver(&fhc_driver, &of_platform_bus_type);
|
|
(void) of_register_driver(&clock_board_driver, &of_platform_bus_type);
|
|
return 0;
|
|
}
|
|
|
|
subsys_initcall(sunfire_init);
|