1 /* 2 * Broadcom specific AMBA 3 * Broadcom MIPS32 74K core driver 4 * 5 * Copyright 2009, Broadcom Corporation 6 * Copyright 2006, 2007, Michael Buesch <mb@bu3sch.de> 7 * Copyright 2010, Bernhard Loos <bernhardloos@googlemail.com> 8 * Copyright 2011, Hauke Mehrtens <hauke@hauke-m.de> 9 * 10 * Licensed under the GNU/GPL. See COPYING for details. 11 */ 12 13 #include "bcma_private.h" 14 15 #include <linux/bcma/bcma.h> 16 17 #include <linux/serial.h> 18 #include <linux/serial_core.h> 19 #include <linux/serial_reg.h> 20 #include <linux/time.h> 21 22 /* The 47162a0 hangs when reading MIPS DMP registers registers */ 23 static inline bool bcma_core_mips_bcm47162a0_quirk(struct bcma_device *dev) 24 { 25 return dev->bus->chipinfo.id == BCMA_CHIP_ID_BCM47162 && 26 dev->bus->chipinfo.rev == 0 && dev->id.id == BCMA_CORE_MIPS_74K; 27 } 28 29 /* The 5357b0 hangs when reading USB20H DMP registers */ 30 static inline bool bcma_core_mips_bcm5357b0_quirk(struct bcma_device *dev) 31 { 32 return (dev->bus->chipinfo.id == BCMA_CHIP_ID_BCM5357 || 33 dev->bus->chipinfo.id == BCMA_CHIP_ID_BCM4749) && 34 dev->bus->chipinfo.pkg == 11 && 35 dev->id.id == BCMA_CORE_USB20_HOST; 36 } 37 38 static inline u32 mips_read32(struct bcma_drv_mips *mcore, 39 u16 offset) 40 { 41 return bcma_read32(mcore->core, offset); 42 } 43 44 static inline void mips_write32(struct bcma_drv_mips *mcore, 45 u16 offset, 46 u32 value) 47 { 48 bcma_write32(mcore->core, offset, value); 49 } 50 51 static const u32 ipsflag_irq_mask[] = { 52 0, 53 BCMA_MIPS_IPSFLAG_IRQ1, 54 BCMA_MIPS_IPSFLAG_IRQ2, 55 BCMA_MIPS_IPSFLAG_IRQ3, 56 BCMA_MIPS_IPSFLAG_IRQ4, 57 }; 58 59 static const u32 ipsflag_irq_shift[] = { 60 0, 61 BCMA_MIPS_IPSFLAG_IRQ1_SHIFT, 62 BCMA_MIPS_IPSFLAG_IRQ2_SHIFT, 63 BCMA_MIPS_IPSFLAG_IRQ3_SHIFT, 64 BCMA_MIPS_IPSFLAG_IRQ4_SHIFT, 65 }; 66 67 static u32 bcma_core_mips_irqflag(struct bcma_device *dev) 68 { 69 u32 flag; 70 71 if (bcma_core_mips_bcm47162a0_quirk(dev)) 72 return dev->core_index; 73 if (bcma_core_mips_bcm5357b0_quirk(dev)) 74 return dev->core_index; 75 flag = bcma_aread32(dev, BCMA_MIPS_OOBSELOUTA30); 76 77 return flag & 0x1F; 78 } 79 80 /* Get the MIPS IRQ assignment for a specified device. 81 * If unassigned, 0 is returned. 82 */ 83 unsigned int bcma_core_mips_irq(struct bcma_device *dev) 84 { 85 struct bcma_device *mdev = dev->bus->drv_mips.core; 86 u32 irqflag; 87 unsigned int irq; 88 89 irqflag = bcma_core_mips_irqflag(dev); 90 91 for (irq = 1; irq <= 4; irq++) 92 if (bcma_read32(mdev, BCMA_MIPS_MIPS74K_INTMASK(irq)) & 93 (1 << irqflag)) 94 return irq; 95 96 return 0; 97 } 98 EXPORT_SYMBOL(bcma_core_mips_irq); 99 100 static void bcma_core_mips_set_irq(struct bcma_device *dev, unsigned int irq) 101 { 102 unsigned int oldirq = bcma_core_mips_irq(dev); 103 struct bcma_bus *bus = dev->bus; 104 struct bcma_device *mdev = bus->drv_mips.core; 105 u32 irqflag; 106 107 irqflag = bcma_core_mips_irqflag(dev); 108 BUG_ON(oldirq == 6); 109 110 dev->irq = irq + 2; 111 112 /* clear the old irq */ 113 if (oldirq == 0) 114 bcma_write32(mdev, BCMA_MIPS_MIPS74K_INTMASK(0), 115 bcma_read32(mdev, BCMA_MIPS_MIPS74K_INTMASK(0)) & 116 ~(1 << irqflag)); 117 else 118 bcma_write32(mdev, BCMA_MIPS_MIPS74K_INTMASK(oldirq), 0); 119 120 /* assign the new one */ 121 if (irq == 0) { 122 bcma_write32(mdev, BCMA_MIPS_MIPS74K_INTMASK(0), 123 bcma_read32(mdev, BCMA_MIPS_MIPS74K_INTMASK(0)) | 124 (1 << irqflag)); 125 } else { 126 u32 oldirqflag = bcma_read32(mdev, 127 BCMA_MIPS_MIPS74K_INTMASK(irq)); 128 if (oldirqflag) { 129 struct bcma_device *core; 130 131 /* backplane irq line is in use, find out who uses 132 * it and set user to irq 0 133 */ 134 list_for_each_entry(core, &bus->cores, list) { 135 if ((1 << bcma_core_mips_irqflag(core)) == 136 oldirqflag) { 137 bcma_core_mips_set_irq(core, 0); 138 break; 139 } 140 } 141 } 142 bcma_write32(mdev, BCMA_MIPS_MIPS74K_INTMASK(irq), 143 1 << irqflag); 144 } 145 146 bcma_info(bus, "set_irq: core 0x%04x, irq %d => %d\n", 147 dev->id.id, oldirq + 2, irq + 2); 148 } 149 150 static void bcma_core_mips_print_irq(struct bcma_device *dev, unsigned int irq) 151 { 152 int i; 153 static const char *irq_name[] = {"2(S)", "3", "4", "5", "6", "D", "I"}; 154 printk(KERN_INFO KBUILD_MODNAME ": core 0x%04x, irq :", dev->id.id); 155 for (i = 0; i <= 6; i++) 156 printk(" %s%s", irq_name[i], i == irq ? "*" : " "); 157 printk("\n"); 158 } 159 160 static void bcma_core_mips_dump_irq(struct bcma_bus *bus) 161 { 162 struct bcma_device *core; 163 164 list_for_each_entry(core, &bus->cores, list) { 165 bcma_core_mips_print_irq(core, bcma_core_mips_irq(core)); 166 } 167 } 168 169 u32 bcma_cpu_clock(struct bcma_drv_mips *mcore) 170 { 171 struct bcma_bus *bus = mcore->core->bus; 172 173 if (bus->drv_cc.capabilities & BCMA_CC_CAP_PMU) 174 return bcma_pmu_get_cpu_clock(&bus->drv_cc); 175 176 bcma_err(bus, "No PMU available, need this to get the cpu clock\n"); 177 return 0; 178 } 179 EXPORT_SYMBOL(bcma_cpu_clock); 180 181 static void bcma_core_mips_flash_detect(struct bcma_drv_mips *mcore) 182 { 183 struct bcma_bus *bus = mcore->core->bus; 184 struct bcma_drv_cc *cc = &bus->drv_cc; 185 186 switch (cc->capabilities & BCMA_CC_CAP_FLASHT) { 187 case BCMA_CC_FLASHT_STSER: 188 case BCMA_CC_FLASHT_ATSER: 189 bcma_debug(bus, "Found serial flash\n"); 190 bcma_sflash_init(cc); 191 break; 192 case BCMA_CC_FLASHT_PARA: 193 bcma_debug(bus, "Found parallel flash\n"); 194 cc->pflash.present = true; 195 cc->pflash.window = BCMA_SOC_FLASH2; 196 cc->pflash.window_size = BCMA_SOC_FLASH2_SZ; 197 198 if ((bcma_read32(cc->core, BCMA_CC_FLASH_CFG) & 199 BCMA_CC_FLASH_CFG_DS) == 0) 200 cc->pflash.buswidth = 1; 201 else 202 cc->pflash.buswidth = 2; 203 break; 204 default: 205 bcma_err(bus, "Flash type not supported\n"); 206 } 207 208 if (cc->core->id.rev == 38 || 209 bus->chipinfo.id == BCMA_CHIP_ID_BCM4706) { 210 if (cc->capabilities & BCMA_CC_CAP_NFLASH) { 211 bcma_debug(bus, "Found NAND flash\n"); 212 bcma_nflash_init(cc); 213 } 214 } 215 } 216 217 void bcma_core_mips_early_init(struct bcma_drv_mips *mcore) 218 { 219 struct bcma_bus *bus = mcore->core->bus; 220 221 if (mcore->early_setup_done) 222 return; 223 224 bcma_chipco_serial_init(&bus->drv_cc); 225 bcma_core_mips_flash_detect(mcore); 226 227 mcore->early_setup_done = true; 228 } 229 230 void bcma_core_mips_init(struct bcma_drv_mips *mcore) 231 { 232 struct bcma_bus *bus; 233 struct bcma_device *core; 234 bus = mcore->core->bus; 235 236 if (mcore->setup_done) 237 return; 238 239 bcma_info(bus, "Initializing MIPS core...\n"); 240 241 bcma_core_mips_early_init(mcore); 242 243 mcore->assigned_irqs = 1; 244 245 /* Assign IRQs to all cores on the bus */ 246 list_for_each_entry(core, &bus->cores, list) { 247 int mips_irq; 248 if (core->irq) 249 continue; 250 251 mips_irq = bcma_core_mips_irq(core); 252 if (mips_irq > 4) 253 core->irq = 0; 254 else 255 core->irq = mips_irq + 2; 256 if (core->irq > 5) 257 continue; 258 switch (core->id.id) { 259 case BCMA_CORE_PCI: 260 case BCMA_CORE_PCIE: 261 case BCMA_CORE_ETHERNET: 262 case BCMA_CORE_ETHERNET_GBIT: 263 case BCMA_CORE_MAC_GBIT: 264 case BCMA_CORE_80211: 265 case BCMA_CORE_USB20_HOST: 266 /* These devices get their own IRQ line if available, 267 * the rest goes on IRQ0 268 */ 269 if (mcore->assigned_irqs <= 4) 270 bcma_core_mips_set_irq(core, 271 mcore->assigned_irqs++); 272 break; 273 } 274 } 275 bcma_info(bus, "IRQ reconfiguration done\n"); 276 bcma_core_mips_dump_irq(bus); 277 278 mcore->setup_done = true; 279 } 280