1 /* $NetBSD: dbau1550.c,v 1.8 2007/01/24 13:08:14 hubertf Exp $ */ 2 3 /*- 4 * Copyright (c) 2006 Itronix Inc. 5 * All rights reserved. 6 * 7 * Written by Garrett D'Amore for Itronix Inc. 8 * 9 * Redistribution and use in source and binary forms, with or without 10 * modification, are permitted provided that the following conditions 11 * are met: 12 * 1. Redistributions of source code must retain the above copyright 13 * notice, this list of conditions and the following disclaimer. 14 * 2. Redistributions in binary form must reproduce the above copyright 15 * notice, this list of conditions and the following disclaimer in the 16 * documentation and/or other materials provided with the distribution. 17 * 3. The name of Itronix Inc. may not be used to endorse 18 * or promote products derived from this software without specific 19 * prior written permission. 20 * 21 * THIS SOFTWARE IS PROVIDED BY ITRONIX INC. ``AS IS'' AND 22 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED 23 * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR 24 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL ITRONIX INC. BE LIABLE FOR ANY 25 * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES 26 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; 27 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND 28 * ON ANY THEORY OF LIABILITY, WHETHER IN 29 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 30 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 31 * POSSIBILITY OF SUCH DAMAGE. 32 */ 33 34 #include <sys/cdefs.h> 35 __KERNEL_RCSID(0, "$NetBSD: dbau1550.c,v 1.8 2007/01/24 13:08:14 hubertf Exp $"); 36 37 #include <sys/param.h> 38 #include <sys/kernel.h> 39 #include <sys/time.h> 40 #include <sys/proc.h> 41 #include <machine/bus.h> 42 #include <machine/locore.h> 43 #include <mips/alchemy/include/aureg.h> 44 #include <mips/alchemy/dev/aupcmciavar.h> 45 #include <mips/alchemy/dev/aupcmciareg.h> 46 #include <mips/alchemy/dev/augpioreg.h> 47 #include <mips/alchemy/dev/auspivar.h> 48 #include <evbmips/alchemy/obiovar.h> 49 #include <evbmips/alchemy/board.h> 50 #include <evbmips/alchemy/dbau1550reg.h> 51 52 #include "auspi.h" 53 54 /* 55 * This should be converted to use bus_space routines. 56 */ 57 #define GET16(x) \ 58 (*((volatile uint16_t *)MIPS_PHYS_TO_KSEG1(x))) 59 #define PUT16(x, v) \ 60 (*((volatile uint16_t *)MIPS_PHYS_TO_KSEG1(x)) = (v)) 61 #define GET32(x) \ 62 (*((volatile uint32_t *)MIPS_PHYS_TO_KSEG1(x))) 63 #define PUT32(x, v) \ 64 (*((volatile uint32_t *)MIPS_PHYS_TO_KSEG1(x)) = (v)) 65 66 static void dbau1550_init(void); 67 static int dbau1550_pci_intr_map(struct pci_attach_args *, 68 pci_intr_handle_t *); 69 static void dbau1550_poweroff(void); 70 static void dbau1550_reboot(void); 71 static bus_addr_t dbau1550_slot_offset(int); 72 static int dbau1550_slot_irq(int, int); 73 static void dbau1550_slot_enable(int); 74 static void dbau1550_slot_disable(int); 75 static int dbau1550_slot_status(int); 76 static const char *dbau1550_slot_name(int); 77 static const struct auspi_machdep *dbau1550_spi(bus_addr_t); 78 79 static const struct obiodev dbau1550_devices[] = { 80 { NULL }, 81 }; 82 83 static struct aupcmcia_machdep dbau1550_pcmcia = { 84 2, /* nslots */ 85 dbau1550_slot_offset, 86 dbau1550_slot_irq, 87 dbau1550_slot_enable, 88 dbau1550_slot_disable, 89 dbau1550_slot_status, 90 dbau1550_slot_name, 91 }; 92 93 static struct alchemy_board dbau1550_info = { 94 .ab_name = "AMD Alchemy DBAu1550", 95 .ab_devices = dbau1550_devices, 96 .ab_init = dbau1550_init, 97 .ab_pci_intr_map =dbau1550_pci_intr_map, 98 .ab_reboot = dbau1550_reboot, 99 .ab_poweroff = dbau1550_poweroff, 100 .ab_pcmcia = &dbau1550_pcmcia, 101 .ab_spi = dbau1550_spi, 102 }; 103 104 const struct alchemy_board * 105 board_info(void) 106 { 107 108 return &dbau1550_info; 109 } 110 111 void 112 dbau1550_init(void) 113 { 114 uint16_t whoami; 115 uint32_t sysclk; 116 uint32_t pinfunc; 117 118 if (MIPS_PRID_COPTS(cpu_id) != MIPS_AU1550) 119 panic("dbau1550: CPU not Au1550"); 120 121 /* check the whoami register for a match */ 122 whoami = GET16(DBAU1550_WHOAMI); 123 124 if (DBAU1550_WHOAMI_BOARD(whoami) != DBAU1550_WHOAMI_DBAU1550_REV1) 125 panic("dbau1550: WHOAMI (%x) not DBAu1550!", whoami); 126 127 printf("DBAu1550 (cabernet), CPLDv%d, ", 128 DBAU1550_WHOAMI_CPLD(whoami)); 129 130 if (DBAU1550_WHOAMI_DAUGHTER(whoami) != 0xf) 131 printf("daughtercard 0x%x\n", 132 DBAU1550_WHOAMI_DAUGHTER(whoami)); 133 else 134 printf("no daughtercard\n"); 135 136 /* leave console and clocks alone -- YAMON should have got it right! */ 137 138 /* 139 * Initialize PSC clocks. 140 * 141 * PSC0 is SPI. Use 48MHz FREQ1. 142 * PSC1 is AC97. 143 * PSC2 is SMBus, and must be 48MHz. (Configured by YAMON) 144 * PSC3 is I2S. 145 * 146 * FREQ2 is 48MHz for USBH/USBD. 147 */ 148 sysclk = GET32(SYS_CLKSRC); 149 sysclk &= ~(SCS_MP0(7) | SCS_DP0 | SCS_CP0); 150 sysclk |= SCS_MP0(3); 151 PUT32(SYS_CLKSRC, sysclk); 152 153 /* 154 * Configure pin function for PSC devices. 155 */ 156 pinfunc = GET32(SYS_PINFUNC); 157 /* configure PSC0 SYNC1 */ 158 pinfunc |= SPF_S0; 159 /* configure PSC2 for SMBus (YAMON default) */ 160 pinfunc &= ~SPF_PSC2_MASK; 161 pinfunc |= SPF_PSC2_SMBUS; 162 /* configure PSC3 for I2S (YAMON default) */ 163 pinfunc &= ~SPF_PSC3_MASK; 164 pinfunc |= SPF_PSC3_I2S; 165 PUT32(SYS_PINFUNC, pinfunc); 166 } 167 168 int 169 dbau1550_pci_intr_map(struct pci_attach_args *pa, pci_intr_handle_t *ihp) 170 { 171 /* 172 * This platform has one onboard PCI IDE controller, and two 173 * PCI expansion slots. 174 */ 175 static const int irqmap[3/*device*/][4/*pin*/] = { 176 { 5, -1, -1, -1 }, /* 11: IDE */ 177 { 2, 5, 6, 1 }, /* 12: PCI Slot 2 */ 178 { 1, 2, 5, 6 }, /* 13: PCI Slot 3 */ 179 }; 180 int pin, dev, irq; 181 182 /* if interrupt pin not used... */ 183 if ((pin = pa->pa_intrpin) == 0) 184 return 1; 185 186 if (pin > 4) { 187 printf("pci: bad interrupt pin %d\n", pin); 188 return 1; 189 } 190 191 pci_decompose_tag(pa->pa_pc, pa->pa_intrtag, NULL, &dev, NULL); 192 if ((dev < 11) || (dev > 13)) { 193 printf("pci: bad device %d\n", dev); 194 return 1; 195 } 196 197 if ((irq = irqmap[dev - 11][pin - 1]) == -1) { 198 printf("pci: no IRQ routing for device %d pin %d\n", dev, pin); 199 return 1; 200 } 201 202 *ihp = irq; 203 return 0; 204 } 205 206 void 207 dbau1550_reboot(void) 208 { 209 PUT16(DBAU1550_SOFTWARE_RESET, 0); 210 wbflush(); 211 delay(100000); /* 100 msec */ 212 } 213 214 void 215 dbau1550_poweroff(void) 216 { 217 printf("\n- poweroff -\n"); 218 PUT16(DBAU1550_SOFTWARE_RESET, 219 DBAU1550_SOFTWARE_RESET_PWROFF | DBAU1550_SOFTWARE_RESET_RESET); 220 wbflush(); 221 delay(100000); /* 100 msec */ 222 } 223 224 int 225 dbau1550_slot_irq(int slot, int which) 226 { 227 static const int irqmap[2/*slot*/][2/*which*/] = { 228 { 35, 32 }, /* Slot 0: Bottom */ 229 { 37, 33 }, /* Slot 1: Top */ 230 }; 231 232 if ((slot >= 2) || (which >= 2)) 233 return -1; 234 235 return (irqmap[slot][which]); 236 } 237 238 bus_addr_t 239 dbau1550_slot_offset(int slot) 240 { 241 switch (slot) { 242 case 0: 243 return (DBAU1550_PC0_ADDR); 244 case 1: 245 return (DBAU1550_PC1_ADDR); 246 } 247 248 return (bus_addr_t)-1; 249 } 250 251 void 252 dbau1550_slot_enable(int slot) 253 { 254 uint16_t status; 255 uint16_t vcc, vpp; 256 int shift; 257 258 status = GET16(DBAU1550_STATUS); 259 switch (slot) { 260 case 0: 261 status >>= DBAU1550_STATUS_PCMCIA0_VS_SHIFT; 262 shift = DBAU1550_PCMCIA_PC0_SHIFT; 263 break; 264 case 1: 265 status >>= DBAU1550_STATUS_PCMCIA1_VS_SHIFT; 266 shift = DBAU1550_PCMCIA_PC1_SHIFT; 267 break; 268 default: 269 return; 270 } 271 272 status &= DBAU1550_STATUS_PCMCIA_VS_MASK; 273 switch (status) { 274 case DBAU1550_STATUS_PCMCIA_VS_GND: 275 vcc = DBAU1550_PCMCIA_VCC_GND; 276 vpp = DBAU1550_PCMCIA_VPP_GND; 277 break; 278 case DBAU1550_STATUS_PCMCIA_VS_5V: 279 vcc = DBAU1550_PCMCIA_VCC_5V; 280 vpp = DBAU1550_PCMCIA_VPP_VCC; 281 break; 282 default: /* covers both 3.3v cases */ 283 vcc = DBAU1550_PCMCIA_VCC_3V; 284 vpp = DBAU1550_PCMCIA_VPP_VCC; 285 break; 286 } 287 288 status = GET16(DBAU1550_PCMCIA); 289 290 /* this clears all bits for this slot */ 291 status &= ~(DBAU1550_PCMCIA_MASK << shift); 292 293 status |= vcc << shift; 294 status |= vpp << shift; 295 296 PUT16(DBAU1550_PCMCIA, status); 297 wbflush(); 298 tsleep(&status, PWAIT, "pcmcia_reset_0", mstohz(100)); 299 300 status |= (DBAU1550_PCMCIA_DRV_EN << shift); 301 PUT16(DBAU1550_PCMCIA, status); 302 wbflush(); 303 tsleep(&status, PWAIT, "pcmcia_reset_start", mstohz(300)); 304 305 /* take it out of reset */ 306 status |= (DBAU1550_PCMCIA_RST << shift); 307 PUT16(DBAU1550_PCMCIA, status); 308 wbflush(); 309 310 /* spec says 20 msec, but experience shows even 200 is not enough */ 311 tsleep(&status, PWAIT, "pcmcia_reset_finish", mstohz(1000)); 312 313 /* NOTE: WE DO NOT SUPPORT DIFFERENT VCC/VPP LEVELS! */ 314 /* This means that 12V cards are not supported! */ 315 } 316 317 void 318 dbau1550_slot_disable(int slot) 319 { 320 int shift; 321 uint16_t status; 322 323 switch (slot) { 324 case 0: 325 shift = DBAU1550_PCMCIA_PC0_SHIFT; 326 break; 327 case 1: 328 shift = DBAU1550_PCMCIA_PC1_SHIFT; 329 break; 330 } 331 332 status = GET16(DBAU1550_PCMCIA); 333 status &= ~(DBAU1550_PCMCIA_MASK); 334 PUT16(DBAU1550_PCMCIA, status); 335 wbflush(); 336 } 337 338 int 339 dbau1550_slot_status(int slot) 340 { 341 uint16_t status, mask; 342 status = GET16(DBAU1550_STATUS); 343 switch (slot) { 344 case 0: 345 mask = DBAU1550_STATUS_PCMCIA0_INSERTED; 346 break; 347 case 1: 348 mask = DBAU1550_STATUS_PCMCIA1_INSERTED; 349 break; 350 351 default: 352 return 0; 353 } 354 355 return ((mask & status) ? 0 : 1); 356 } 357 358 const char * 359 dbau1550_slot_name(int slot) 360 { 361 switch (slot) { 362 case 0: 363 return "bottom slot"; 364 case 1: 365 return "top slot"; 366 default: 367 return "???"; 368 } 369 } 370 371 #if NAUSPI > 0 372 373 static int 374 dbau1550_spi_select(void *arg, int slave) 375 { 376 uint16_t status; 377 if ((slave < 0) || (slave > 1)) 378 return EINVAL; 379 status = GET16(DBAU1550_BOARD_SPECIFIC); 380 381 if (slave) { 382 status |= DBAU1550_SPI_DEV_SEL; 383 } else { 384 status &= ~DBAU1550_SPI_DEV_SEL; 385 } 386 PUT16(DBAU1550_BOARD_SPECIFIC, status); 387 return 0; 388 } 389 390 const struct auspi_machdep * 391 dbau1550_spi(bus_addr_t ba) 392 { 393 static const struct auspi_machdep md = { 394 .am_nslaves = 2, 395 .am_cookie = NULL, 396 .am_select = dbau1550_spi_select, 397 }; 398 399 /* DBAU1550 only has SPI on PSC0 */ 400 if (ba != PSC0_BASE) 401 return NULL; 402 403 return &md; 404 } 405 406 #endif /* NAUSPI > 0 */ 407