1*a88b5ba8SSam Ravnborg /* central.c: Central FHC driver for Sunfire/Starfire/Wildfire. 2*a88b5ba8SSam Ravnborg * 3*a88b5ba8SSam Ravnborg * Copyright (C) 1997, 1999, 2008 David S. Miller (davem@davemloft.net) 4*a88b5ba8SSam Ravnborg */ 5*a88b5ba8SSam Ravnborg 6*a88b5ba8SSam Ravnborg #include <linux/kernel.h> 7*a88b5ba8SSam Ravnborg #include <linux/types.h> 8*a88b5ba8SSam Ravnborg #include <linux/string.h> 9*a88b5ba8SSam Ravnborg #include <linux/init.h> 10*a88b5ba8SSam Ravnborg #include <linux/of_device.h> 11*a88b5ba8SSam Ravnborg #include <linux/platform_device.h> 12*a88b5ba8SSam Ravnborg 13*a88b5ba8SSam Ravnborg #include <asm/fhc.h> 14*a88b5ba8SSam Ravnborg #include <asm/upa.h> 15*a88b5ba8SSam Ravnborg 16*a88b5ba8SSam Ravnborg struct clock_board { 17*a88b5ba8SSam Ravnborg void __iomem *clock_freq_regs; 18*a88b5ba8SSam Ravnborg void __iomem *clock_regs; 19*a88b5ba8SSam Ravnborg void __iomem *clock_ver_reg; 20*a88b5ba8SSam Ravnborg int num_slots; 21*a88b5ba8SSam Ravnborg struct resource leds_resource; 22*a88b5ba8SSam Ravnborg struct platform_device leds_pdev; 23*a88b5ba8SSam Ravnborg }; 24*a88b5ba8SSam Ravnborg 25*a88b5ba8SSam Ravnborg struct fhc { 26*a88b5ba8SSam Ravnborg void __iomem *pregs; 27*a88b5ba8SSam Ravnborg bool central; 28*a88b5ba8SSam Ravnborg bool jtag_master; 29*a88b5ba8SSam Ravnborg int board_num; 30*a88b5ba8SSam Ravnborg struct resource leds_resource; 31*a88b5ba8SSam Ravnborg struct platform_device leds_pdev; 32*a88b5ba8SSam Ravnborg }; 33*a88b5ba8SSam Ravnborg 34*a88b5ba8SSam Ravnborg static int __devinit clock_board_calc_nslots(struct clock_board *p) 35*a88b5ba8SSam Ravnborg { 36*a88b5ba8SSam Ravnborg u8 reg = upa_readb(p->clock_regs + CLOCK_STAT1) & 0xc0; 37*a88b5ba8SSam Ravnborg 38*a88b5ba8SSam Ravnborg switch (reg) { 39*a88b5ba8SSam Ravnborg case 0x40: 40*a88b5ba8SSam Ravnborg return 16; 41*a88b5ba8SSam Ravnborg 42*a88b5ba8SSam Ravnborg case 0xc0: 43*a88b5ba8SSam Ravnborg return 8; 44*a88b5ba8SSam Ravnborg 45*a88b5ba8SSam Ravnborg case 0x80: 46*a88b5ba8SSam Ravnborg reg = 0; 47*a88b5ba8SSam Ravnborg if (p->clock_ver_reg) 48*a88b5ba8SSam Ravnborg reg = upa_readb(p->clock_ver_reg); 49*a88b5ba8SSam Ravnborg if (reg) { 50*a88b5ba8SSam Ravnborg if (reg & 0x80) 51*a88b5ba8SSam Ravnborg return 4; 52*a88b5ba8SSam Ravnborg else 53*a88b5ba8SSam Ravnborg return 5; 54*a88b5ba8SSam Ravnborg } 55*a88b5ba8SSam Ravnborg /* Fallthrough */ 56*a88b5ba8SSam Ravnborg default: 57*a88b5ba8SSam Ravnborg return 4; 58*a88b5ba8SSam Ravnborg } 59*a88b5ba8SSam Ravnborg } 60*a88b5ba8SSam Ravnborg 61*a88b5ba8SSam Ravnborg static int __devinit clock_board_probe(struct of_device *op, 62*a88b5ba8SSam Ravnborg const struct of_device_id *match) 63*a88b5ba8SSam Ravnborg { 64*a88b5ba8SSam Ravnborg struct clock_board *p = kzalloc(sizeof(*p), GFP_KERNEL); 65*a88b5ba8SSam Ravnborg int err = -ENOMEM; 66*a88b5ba8SSam Ravnborg 67*a88b5ba8SSam Ravnborg if (!p) { 68*a88b5ba8SSam Ravnborg printk(KERN_ERR "clock_board: Cannot allocate struct clock_board\n"); 69*a88b5ba8SSam Ravnborg goto out; 70*a88b5ba8SSam Ravnborg } 71*a88b5ba8SSam Ravnborg 72*a88b5ba8SSam Ravnborg p->clock_freq_regs = of_ioremap(&op->resource[0], 0, 73*a88b5ba8SSam Ravnborg resource_size(&op->resource[0]), 74*a88b5ba8SSam Ravnborg "clock_board_freq"); 75*a88b5ba8SSam Ravnborg if (!p->clock_freq_regs) { 76*a88b5ba8SSam Ravnborg printk(KERN_ERR "clock_board: Cannot map clock_freq_regs\n"); 77*a88b5ba8SSam Ravnborg goto out_free; 78*a88b5ba8SSam Ravnborg } 79*a88b5ba8SSam Ravnborg 80*a88b5ba8SSam Ravnborg p->clock_regs = of_ioremap(&op->resource[1], 0, 81*a88b5ba8SSam Ravnborg resource_size(&op->resource[1]), 82*a88b5ba8SSam Ravnborg "clock_board_regs"); 83*a88b5ba8SSam Ravnborg if (!p->clock_regs) { 84*a88b5ba8SSam Ravnborg printk(KERN_ERR "clock_board: Cannot map clock_regs\n"); 85*a88b5ba8SSam Ravnborg goto out_unmap_clock_freq_regs; 86*a88b5ba8SSam Ravnborg } 87*a88b5ba8SSam Ravnborg 88*a88b5ba8SSam Ravnborg if (op->resource[2].flags) { 89*a88b5ba8SSam Ravnborg p->clock_ver_reg = of_ioremap(&op->resource[2], 0, 90*a88b5ba8SSam Ravnborg resource_size(&op->resource[2]), 91*a88b5ba8SSam Ravnborg "clock_ver_reg"); 92*a88b5ba8SSam Ravnborg if (!p->clock_ver_reg) { 93*a88b5ba8SSam Ravnborg printk(KERN_ERR "clock_board: Cannot map clock_ver_reg\n"); 94*a88b5ba8SSam Ravnborg goto out_unmap_clock_regs; 95*a88b5ba8SSam Ravnborg } 96*a88b5ba8SSam Ravnborg } 97*a88b5ba8SSam Ravnborg 98*a88b5ba8SSam Ravnborg p->num_slots = clock_board_calc_nslots(p); 99*a88b5ba8SSam Ravnborg 100*a88b5ba8SSam Ravnborg p->leds_resource.start = (unsigned long) 101*a88b5ba8SSam Ravnborg (p->clock_regs + CLOCK_CTRL); 102*a88b5ba8SSam Ravnborg p->leds_resource.end = p->leds_resource.end; 103*a88b5ba8SSam Ravnborg p->leds_resource.name = "leds"; 104*a88b5ba8SSam Ravnborg 105*a88b5ba8SSam Ravnborg p->leds_pdev.name = "sunfire-clockboard-leds"; 106*a88b5ba8SSam Ravnborg p->leds_pdev.resource = &p->leds_resource; 107*a88b5ba8SSam Ravnborg p->leds_pdev.num_resources = 1; 108*a88b5ba8SSam Ravnborg p->leds_pdev.dev.parent = &op->dev; 109*a88b5ba8SSam Ravnborg 110*a88b5ba8SSam Ravnborg err = platform_device_register(&p->leds_pdev); 111*a88b5ba8SSam Ravnborg if (err) { 112*a88b5ba8SSam Ravnborg printk(KERN_ERR "clock_board: Could not register LEDS " 113*a88b5ba8SSam Ravnborg "platform device\n"); 114*a88b5ba8SSam Ravnborg goto out_unmap_clock_ver_reg; 115*a88b5ba8SSam Ravnborg } 116*a88b5ba8SSam Ravnborg 117*a88b5ba8SSam Ravnborg printk(KERN_INFO "clock_board: Detected %d slot Enterprise system.\n", 118*a88b5ba8SSam Ravnborg p->num_slots); 119*a88b5ba8SSam Ravnborg 120*a88b5ba8SSam Ravnborg err = 0; 121*a88b5ba8SSam Ravnborg out: 122*a88b5ba8SSam Ravnborg return err; 123*a88b5ba8SSam Ravnborg 124*a88b5ba8SSam Ravnborg out_unmap_clock_ver_reg: 125*a88b5ba8SSam Ravnborg if (p->clock_ver_reg) 126*a88b5ba8SSam Ravnborg of_iounmap(&op->resource[2], p->clock_ver_reg, 127*a88b5ba8SSam Ravnborg resource_size(&op->resource[2])); 128*a88b5ba8SSam Ravnborg 129*a88b5ba8SSam Ravnborg out_unmap_clock_regs: 130*a88b5ba8SSam Ravnborg of_iounmap(&op->resource[1], p->clock_regs, 131*a88b5ba8SSam Ravnborg resource_size(&op->resource[1])); 132*a88b5ba8SSam Ravnborg 133*a88b5ba8SSam Ravnborg out_unmap_clock_freq_regs: 134*a88b5ba8SSam Ravnborg of_iounmap(&op->resource[0], p->clock_freq_regs, 135*a88b5ba8SSam Ravnborg resource_size(&op->resource[0])); 136*a88b5ba8SSam Ravnborg 137*a88b5ba8SSam Ravnborg out_free: 138*a88b5ba8SSam Ravnborg kfree(p); 139*a88b5ba8SSam Ravnborg goto out; 140*a88b5ba8SSam Ravnborg } 141*a88b5ba8SSam Ravnborg 142*a88b5ba8SSam Ravnborg static struct of_device_id __initdata clock_board_match[] = { 143*a88b5ba8SSam Ravnborg { 144*a88b5ba8SSam Ravnborg .name = "clock-board", 145*a88b5ba8SSam Ravnborg }, 146*a88b5ba8SSam Ravnborg {}, 147*a88b5ba8SSam Ravnborg }; 148*a88b5ba8SSam Ravnborg 149*a88b5ba8SSam Ravnborg static struct of_platform_driver clock_board_driver = { 150*a88b5ba8SSam Ravnborg .match_table = clock_board_match, 151*a88b5ba8SSam Ravnborg .probe = clock_board_probe, 152*a88b5ba8SSam Ravnborg .driver = { 153*a88b5ba8SSam Ravnborg .name = "clock_board", 154*a88b5ba8SSam Ravnborg }, 155*a88b5ba8SSam Ravnborg }; 156*a88b5ba8SSam Ravnborg 157*a88b5ba8SSam Ravnborg static int __devinit fhc_probe(struct of_device *op, 158*a88b5ba8SSam Ravnborg const struct of_device_id *match) 159*a88b5ba8SSam Ravnborg { 160*a88b5ba8SSam Ravnborg struct fhc *p = kzalloc(sizeof(*p), GFP_KERNEL); 161*a88b5ba8SSam Ravnborg int err = -ENOMEM; 162*a88b5ba8SSam Ravnborg u32 reg; 163*a88b5ba8SSam Ravnborg 164*a88b5ba8SSam Ravnborg if (!p) { 165*a88b5ba8SSam Ravnborg printk(KERN_ERR "fhc: Cannot allocate struct fhc\n"); 166*a88b5ba8SSam Ravnborg goto out; 167*a88b5ba8SSam Ravnborg } 168*a88b5ba8SSam Ravnborg 169*a88b5ba8SSam Ravnborg if (!strcmp(op->node->parent->name, "central")) 170*a88b5ba8SSam Ravnborg p->central = true; 171*a88b5ba8SSam Ravnborg 172*a88b5ba8SSam Ravnborg p->pregs = of_ioremap(&op->resource[0], 0, 173*a88b5ba8SSam Ravnborg resource_size(&op->resource[0]), 174*a88b5ba8SSam Ravnborg "fhc_pregs"); 175*a88b5ba8SSam Ravnborg if (!p->pregs) { 176*a88b5ba8SSam Ravnborg printk(KERN_ERR "fhc: Cannot map pregs\n"); 177*a88b5ba8SSam Ravnborg goto out_free; 178*a88b5ba8SSam Ravnborg } 179*a88b5ba8SSam Ravnborg 180*a88b5ba8SSam Ravnborg if (p->central) { 181*a88b5ba8SSam Ravnborg reg = upa_readl(p->pregs + FHC_PREGS_BSR); 182*a88b5ba8SSam Ravnborg p->board_num = ((reg >> 16) & 1) | ((reg >> 12) & 0x0e); 183*a88b5ba8SSam Ravnborg } else { 184*a88b5ba8SSam Ravnborg p->board_num = of_getintprop_default(op->node, "board#", -1); 185*a88b5ba8SSam Ravnborg if (p->board_num == -1) { 186*a88b5ba8SSam Ravnborg printk(KERN_ERR "fhc: No board# property\n"); 187*a88b5ba8SSam Ravnborg goto out_unmap_pregs; 188*a88b5ba8SSam Ravnborg } 189*a88b5ba8SSam Ravnborg if (upa_readl(p->pregs + FHC_PREGS_JCTRL) & FHC_JTAG_CTRL_MENAB) 190*a88b5ba8SSam Ravnborg p->jtag_master = true; 191*a88b5ba8SSam Ravnborg } 192*a88b5ba8SSam Ravnborg 193*a88b5ba8SSam Ravnborg if (!p->central) { 194*a88b5ba8SSam Ravnborg p->leds_resource.start = (unsigned long) 195*a88b5ba8SSam Ravnborg (p->pregs + FHC_PREGS_CTRL); 196*a88b5ba8SSam Ravnborg p->leds_resource.end = p->leds_resource.end; 197*a88b5ba8SSam Ravnborg p->leds_resource.name = "leds"; 198*a88b5ba8SSam Ravnborg 199*a88b5ba8SSam Ravnborg p->leds_pdev.name = "sunfire-fhc-leds"; 200*a88b5ba8SSam Ravnborg p->leds_pdev.resource = &p->leds_resource; 201*a88b5ba8SSam Ravnborg p->leds_pdev.num_resources = 1; 202*a88b5ba8SSam Ravnborg p->leds_pdev.dev.parent = &op->dev; 203*a88b5ba8SSam Ravnborg 204*a88b5ba8SSam Ravnborg err = platform_device_register(&p->leds_pdev); 205*a88b5ba8SSam Ravnborg if (err) { 206*a88b5ba8SSam Ravnborg printk(KERN_ERR "fhc: Could not register LEDS " 207*a88b5ba8SSam Ravnborg "platform device\n"); 208*a88b5ba8SSam Ravnborg goto out_unmap_pregs; 209*a88b5ba8SSam Ravnborg } 210*a88b5ba8SSam Ravnborg } 211*a88b5ba8SSam Ravnborg reg = upa_readl(p->pregs + FHC_PREGS_CTRL); 212*a88b5ba8SSam Ravnborg 213*a88b5ba8SSam Ravnborg if (!p->central) 214*a88b5ba8SSam Ravnborg reg |= FHC_CONTROL_IXIST; 215*a88b5ba8SSam Ravnborg 216*a88b5ba8SSam Ravnborg reg &= ~(FHC_CONTROL_AOFF | 217*a88b5ba8SSam Ravnborg FHC_CONTROL_BOFF | 218*a88b5ba8SSam Ravnborg FHC_CONTROL_SLINE); 219*a88b5ba8SSam Ravnborg 220*a88b5ba8SSam Ravnborg upa_writel(reg, p->pregs + FHC_PREGS_CTRL); 221*a88b5ba8SSam Ravnborg upa_readl(p->pregs + FHC_PREGS_CTRL); 222*a88b5ba8SSam Ravnborg 223*a88b5ba8SSam Ravnborg reg = upa_readl(p->pregs + FHC_PREGS_ID); 224*a88b5ba8SSam Ravnborg printk(KERN_INFO "fhc: Board #%d, Version[%x] PartID[%x] Manuf[%x] %s\n", 225*a88b5ba8SSam Ravnborg p->board_num, 226*a88b5ba8SSam Ravnborg (reg & FHC_ID_VERS) >> 28, 227*a88b5ba8SSam Ravnborg (reg & FHC_ID_PARTID) >> 12, 228*a88b5ba8SSam Ravnborg (reg & FHC_ID_MANUF) >> 1, 229*a88b5ba8SSam Ravnborg (p->jtag_master ? 230*a88b5ba8SSam Ravnborg "(JTAG Master)" : 231*a88b5ba8SSam Ravnborg (p->central ? "(Central)" : ""))); 232*a88b5ba8SSam Ravnborg 233*a88b5ba8SSam Ravnborg err = 0; 234*a88b5ba8SSam Ravnborg 235*a88b5ba8SSam Ravnborg out: 236*a88b5ba8SSam Ravnborg return err; 237*a88b5ba8SSam Ravnborg 238*a88b5ba8SSam Ravnborg out_unmap_pregs: 239*a88b5ba8SSam Ravnborg of_iounmap(&op->resource[0], p->pregs, resource_size(&op->resource[0])); 240*a88b5ba8SSam Ravnborg 241*a88b5ba8SSam Ravnborg out_free: 242*a88b5ba8SSam Ravnborg kfree(p); 243*a88b5ba8SSam Ravnborg goto out; 244*a88b5ba8SSam Ravnborg } 245*a88b5ba8SSam Ravnborg 246*a88b5ba8SSam Ravnborg static struct of_device_id __initdata fhc_match[] = { 247*a88b5ba8SSam Ravnborg { 248*a88b5ba8SSam Ravnborg .name = "fhc", 249*a88b5ba8SSam Ravnborg }, 250*a88b5ba8SSam Ravnborg {}, 251*a88b5ba8SSam Ravnborg }; 252*a88b5ba8SSam Ravnborg 253*a88b5ba8SSam Ravnborg static struct of_platform_driver fhc_driver = { 254*a88b5ba8SSam Ravnborg .match_table = fhc_match, 255*a88b5ba8SSam Ravnborg .probe = fhc_probe, 256*a88b5ba8SSam Ravnborg .driver = { 257*a88b5ba8SSam Ravnborg .name = "fhc", 258*a88b5ba8SSam Ravnborg }, 259*a88b5ba8SSam Ravnborg }; 260*a88b5ba8SSam Ravnborg 261*a88b5ba8SSam Ravnborg static int __init sunfire_init(void) 262*a88b5ba8SSam Ravnborg { 263*a88b5ba8SSam Ravnborg (void) of_register_driver(&fhc_driver, &of_platform_bus_type); 264*a88b5ba8SSam Ravnborg (void) of_register_driver(&clock_board_driver, &of_platform_bus_type); 265*a88b5ba8SSam Ravnborg return 0; 266*a88b5ba8SSam Ravnborg } 267*a88b5ba8SSam Ravnborg 268*a88b5ba8SSam Ravnborg subsys_initcall(sunfire_init); 269