0001
0002
0003
0004
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);