Back to home page

OSCL-LXR

 
 

    


0001 // SPDX-License-Identifier: GPL-2.0
0002 /* central.c: Central FHC driver for Sunfire/Starfire/Wildfire.
0003  *
0004  * Copyright (C) 1997, 1999, 2008 David S. Miller (davem@davemloft.net)
0005  */
0006 
0007 #include <linux/kernel.h>
0008 #include <linux/types.h>
0009 #include <linux/slab.h>
0010 #include <linux/export.h>
0011 #include <linux/string.h>
0012 #include <linux/init.h>
0013 #include <linux/of_device.h>
0014 #include <linux/platform_device.h>
0015 
0016 #include <asm/fhc.h>
0017 #include <asm/upa.h>
0018 
0019 struct clock_board {
0020     void __iomem        *clock_freq_regs;
0021     void __iomem        *clock_regs;
0022     void __iomem        *clock_ver_reg;
0023     int         num_slots;
0024     struct resource     leds_resource;
0025     struct platform_device  leds_pdev;
0026 };
0027 
0028 struct fhc {
0029     void __iomem        *pregs;
0030     bool            central;
0031     bool            jtag_master;
0032     int         board_num;
0033     struct resource     leds_resource;
0034     struct platform_device  leds_pdev;
0035 };
0036 
0037 static int clock_board_calc_nslots(struct clock_board *p)
0038 {
0039     u8 reg = upa_readb(p->clock_regs + CLOCK_STAT1) & 0xc0;
0040 
0041     switch (reg) {
0042     case 0x40:
0043         return 16;
0044 
0045     case 0xc0:
0046         return 8;
0047 
0048     case 0x80:
0049         reg = 0;
0050         if (p->clock_ver_reg)
0051             reg = upa_readb(p->clock_ver_reg);
0052         if (reg) {
0053             if (reg & 0x80)
0054                 return 4;
0055             else
0056                 return 5;
0057         }
0058         fallthrough;
0059     default:
0060         return 4;
0061     }
0062 }
0063 
0064 static int clock_board_probe(struct platform_device *op)
0065 {
0066     struct clock_board *p = kzalloc(sizeof(*p), GFP_KERNEL);
0067     int err = -ENOMEM;
0068 
0069     if (!p) {
0070         printk(KERN_ERR "clock_board: Cannot allocate struct clock_board\n");
0071         goto out;
0072     }
0073 
0074     p->clock_freq_regs = of_ioremap(&op->resource[0], 0,
0075                     resource_size(&op->resource[0]),
0076                     "clock_board_freq");
0077     if (!p->clock_freq_regs) {
0078         printk(KERN_ERR "clock_board: Cannot map clock_freq_regs\n");
0079         goto out_free;
0080     }
0081 
0082     p->clock_regs = of_ioremap(&op->resource[1], 0,
0083                    resource_size(&op->resource[1]),
0084                    "clock_board_regs");
0085     if (!p->clock_regs) {
0086         printk(KERN_ERR "clock_board: Cannot map clock_regs\n");
0087         goto out_unmap_clock_freq_regs;
0088     }
0089 
0090     if (op->resource[2].flags) {
0091         p->clock_ver_reg = of_ioremap(&op->resource[2], 0,
0092                           resource_size(&op->resource[2]),
0093                           "clock_ver_reg");
0094         if (!p->clock_ver_reg) {
0095             printk(KERN_ERR "clock_board: Cannot map clock_ver_reg\n");
0096             goto out_unmap_clock_regs;
0097         }
0098     }
0099 
0100     p->num_slots = clock_board_calc_nslots(p);
0101 
0102     p->leds_resource.start = (unsigned long)
0103         (p->clock_regs + CLOCK_CTRL);
0104     p->leds_resource.end = p->leds_resource.start;
0105     p->leds_resource.name = "leds";
0106 
0107     p->leds_pdev.name = "sunfire-clockboard-leds";
0108     p->leds_pdev.id = -1;
0109     p->leds_pdev.resource = &p->leds_resource;
0110     p->leds_pdev.num_resources = 1;
0111     p->leds_pdev.dev.parent = &op->dev;
0112 
0113     err = platform_device_register(&p->leds_pdev);
0114     if (err) {
0115         printk(KERN_ERR "clock_board: Could not register LEDS "
0116                "platform device\n");
0117         goto out_unmap_clock_ver_reg;
0118     }
0119 
0120     printk(KERN_INFO "clock_board: Detected %d slot Enterprise system.\n",
0121            p->num_slots);
0122 
0123     err = 0;
0124 out:
0125     return err;
0126 
0127 out_unmap_clock_ver_reg:
0128     if (p->clock_ver_reg)
0129         of_iounmap(&op->resource[2], p->clock_ver_reg,
0130                resource_size(&op->resource[2]));
0131 
0132 out_unmap_clock_regs:
0133     of_iounmap(&op->resource[1], p->clock_regs,
0134            resource_size(&op->resource[1]));
0135 
0136 out_unmap_clock_freq_regs:
0137     of_iounmap(&op->resource[0], p->clock_freq_regs,
0138            resource_size(&op->resource[0]));
0139 
0140 out_free:
0141     kfree(p);
0142     goto out;
0143 }
0144 
0145 static const struct of_device_id clock_board_match[] = {
0146     {
0147         .name = "clock-board",
0148     },
0149     {},
0150 };
0151 
0152 static struct platform_driver clock_board_driver = {
0153     .probe      = clock_board_probe,
0154     .driver = {
0155         .name = "clock_board",
0156         .of_match_table = clock_board_match,
0157     },
0158 };
0159 
0160 static int fhc_probe(struct platform_device *op)
0161 {
0162     struct fhc *p = kzalloc(sizeof(*p), GFP_KERNEL);
0163     int err = -ENOMEM;
0164     u32 reg;
0165 
0166     if (!p) {
0167         printk(KERN_ERR "fhc: Cannot allocate struct fhc\n");
0168         goto out;
0169     }
0170 
0171     if (of_node_name_eq(op->dev.of_node->parent, "central"))
0172         p->central = true;
0173 
0174     p->pregs = of_ioremap(&op->resource[0], 0,
0175                   resource_size(&op->resource[0]),
0176                   "fhc_pregs");
0177     if (!p->pregs) {
0178         printk(KERN_ERR "fhc: Cannot map pregs\n");
0179         goto out_free;
0180     }
0181 
0182     if (p->central) {
0183         reg = upa_readl(p->pregs + FHC_PREGS_BSR);
0184         p->board_num = ((reg >> 16) & 1) | ((reg >> 12) & 0x0e);
0185     } else {
0186         p->board_num = of_getintprop_default(op->dev.of_node, "board#", -1);
0187         if (p->board_num == -1) {
0188             printk(KERN_ERR "fhc: No board# property\n");
0189             goto out_unmap_pregs;
0190         }
0191         if (upa_readl(p->pregs + FHC_PREGS_JCTRL) & FHC_JTAG_CTRL_MENAB)
0192             p->jtag_master = true;
0193     }
0194 
0195     if (!p->central) {
0196         p->leds_resource.start = (unsigned long)
0197             (p->pregs + FHC_PREGS_CTRL);
0198         p->leds_resource.end = p->leds_resource.start;
0199         p->leds_resource.name = "leds";
0200 
0201         p->leds_pdev.name = "sunfire-fhc-leds";
0202         p->leds_pdev.id = p->board_num;
0203         p->leds_pdev.resource = &p->leds_resource;
0204         p->leds_pdev.num_resources = 1;
0205         p->leds_pdev.dev.parent = &op->dev;
0206 
0207         err = platform_device_register(&p->leds_pdev);
0208         if (err) {
0209             printk(KERN_ERR "fhc: Could not register LEDS "
0210                    "platform device\n");
0211             goto out_unmap_pregs;
0212         }
0213     }
0214     reg = upa_readl(p->pregs + FHC_PREGS_CTRL);
0215 
0216     if (!p->central)
0217         reg |= FHC_CONTROL_IXIST;
0218 
0219     reg &= ~(FHC_CONTROL_AOFF |
0220          FHC_CONTROL_BOFF |
0221          FHC_CONTROL_SLINE);
0222 
0223     upa_writel(reg, p->pregs + FHC_PREGS_CTRL);
0224     upa_readl(p->pregs + FHC_PREGS_CTRL);
0225 
0226     reg = upa_readl(p->pregs + FHC_PREGS_ID);
0227     printk(KERN_INFO "fhc: Board #%d, Version[%x] PartID[%x] Manuf[%x] %s\n",
0228            p->board_num,
0229            (reg & FHC_ID_VERS) >> 28,
0230            (reg & FHC_ID_PARTID) >> 12,
0231            (reg & FHC_ID_MANUF) >> 1,
0232            (p->jtag_master ?
0233         "(JTAG Master)" :
0234         (p->central ? "(Central)" : "")));
0235 
0236     err = 0;
0237 
0238 out:
0239     return err;
0240 
0241 out_unmap_pregs:
0242     of_iounmap(&op->resource[0], p->pregs, resource_size(&op->resource[0]));
0243 
0244 out_free:
0245     kfree(p);
0246     goto out;
0247 }
0248 
0249 static const struct of_device_id fhc_match[] = {
0250     {
0251         .name = "fhc",
0252     },
0253     {},
0254 };
0255 
0256 static struct platform_driver fhc_driver = {
0257     .probe      = fhc_probe,
0258     .driver = {
0259         .name = "fhc",
0260         .of_match_table = fhc_match,
0261     },
0262 };
0263 
0264 static int __init sunfire_init(void)
0265 {
0266     (void) platform_driver_register(&fhc_driver);
0267     (void) platform_driver_register(&clock_board_driver);
0268     return 0;
0269 }
0270 
0271 fs_initcall(sunfire_init);