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(irq), 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_clockcpu(&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 185 switch (bus->drv_cc.capabilities & BCMA_CC_CAP_FLASHT) { 186 case BCMA_CC_FLASHT_STSER: 187 case BCMA_CC_FLASHT_ATSER: 188 bcma_debug(bus, "Found serial flash\n"); 189 bcma_sflash_init(&bus->drv_cc); 190 break; 191 case BCMA_CC_FLASHT_PARA: 192 bcma_debug(bus, "Found parallel flash\n"); 193 bus->drv_cc.pflash.window = 0x1c000000; 194 bus->drv_cc.pflash.window_size = 0x02000000; 195 196 if ((bcma_read32(bus->drv_cc.core, BCMA_CC_FLASH_CFG) & 197 BCMA_CC_FLASH_CFG_DS) == 0) 198 bus->drv_cc.pflash.buswidth = 1; 199 else 200 bus->drv_cc.pflash.buswidth = 2; 201 break; 202 default: 203 bcma_err(bus, "Flash type not supported\n"); 204 } 205 206 if (bus->drv_cc.core->id.rev == 38 || 207 bus->chipinfo.id == BCMA_CHIP_ID_BCM4706) { 208 if (bus->drv_cc.capabilities & BCMA_CC_CAP_NFLASH) { 209 bcma_debug(bus, "Found NAND flash\n"); 210 bcma_nflash_init(&bus->drv_cc); 211 } 212 } 213 } 214 215 void bcma_core_mips_init(struct bcma_drv_mips *mcore) 216 { 217 struct bcma_bus *bus; 218 struct bcma_device *core; 219 bus = mcore->core->bus; 220 221 bcma_info(bus, "Initializing MIPS core...\n"); 222 223 if (!mcore->setup_done) 224 mcore->assigned_irqs = 1; 225 226 /* Assign IRQs to all cores on the bus */ 227 list_for_each_entry(core, &bus->cores, list) { 228 int mips_irq; 229 if (core->irq) 230 continue; 231 232 mips_irq = bcma_core_mips_irq(core); 233 if (mips_irq > 4) 234 core->irq = 0; 235 else 236 core->irq = mips_irq + 2; 237 if (core->irq > 5) 238 continue; 239 switch (core->id.id) { 240 case BCMA_CORE_PCI: 241 case BCMA_CORE_PCIE: 242 case BCMA_CORE_ETHERNET: 243 case BCMA_CORE_ETHERNET_GBIT: 244 case BCMA_CORE_MAC_GBIT: 245 case BCMA_CORE_80211: 246 case BCMA_CORE_USB20_HOST: 247 /* These devices get their own IRQ line if available, 248 * the rest goes on IRQ0 249 */ 250 if (mcore->assigned_irqs <= 4) 251 bcma_core_mips_set_irq(core, 252 mcore->assigned_irqs++); 253 break; 254 } 255 } 256 bcma_info(bus, "IRQ reconfiguration done\n"); 257 bcma_core_mips_dump_irq(bus); 258 259 if (mcore->setup_done) 260 return; 261 262 bcma_chipco_serial_init(&bus->drv_cc); 263 bcma_core_mips_flash_detect(mcore); 264 mcore->setup_done = true; 265 } 266