Home | History | Annotate | Line # | Download | only in alchemy
dbau1550.c revision 1.6
      1 /* $NetBSD: dbau1550.c,v 1.6 2006/03/25 07:28:20 gdamore 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.6 2006/03/25 07:28:20 gdamore Exp $");
     36 
     37 #include <sys/param.h>
     38 #include <sys/kernel.h>
     39 #include <sys/param.h>
     40 #include <sys/time.h>
     41 #include <sys/proc.h>
     42 #include <machine/bus.h>
     43 #include <machine/locore.h>
     44 #include <mips/alchemy/include/aureg.h>
     45 #include <mips/alchemy/dev/aupcmciavar.h>
     46 #include <mips/alchemy/dev/aupcmciareg.h>
     47 #include <mips/alchemy/dev/augpioreg.h>
     48 #include <evbmips/alchemy/obiovar.h>
     49 #include <evbmips/alchemy/board.h>
     50 #include <evbmips/alchemy/dbau1550reg.h>
     51 
     52 /*
     53  * This should be converted to use bus_space routines.
     54  */
     55 #define	GET16(x)	\
     56 	(*((volatile uint16_t *)MIPS_PHYS_TO_KSEG1(x)))
     57 #define	PUT16(x, v)	\
     58 	(*((volatile uint16_t *)MIPS_PHYS_TO_KSEG1(x)) = (v))
     59 #define	GET32(x)	\
     60 	(*((volatile uint32_t *)MIPS_PHYS_TO_KSEG1(x)))
     61 #define	PUT32(x, v)	\
     62 	(*((volatile uint32_t *)MIPS_PHYS_TO_KSEG1(x)) = (v))
     63 
     64 static void dbau1550_init(void);
     65 static int dbau1550_pci_intr_map(struct pci_attach_args *,
     66 				 pci_intr_handle_t *);
     67 static void dbau1550_poweroff(void);
     68 static void dbau1550_reboot(void);
     69 static bus_addr_t dbau1550_slot_offset(int);
     70 static int dbau1550_slot_irq(int, int);
     71 static void dbau1550_slot_enable(int);
     72 static void dbau1550_slot_disable(int);
     73 static int dbau1550_slot_status(int);
     74 static const char *dbau1550_slot_name(int);
     75 
     76 static const struct obiodev dbau1550_devices[] = {
     77 #if 0
     78 	{ "aupsc", -1, -1 },
     79 	{ "aupsc", -1, -1 },
     80 	{ "aupsc", -1, -1 },
     81 #endif
     82 	{ NULL },
     83 };
     84 
     85 static struct aupcmcia_machdep dbau1550_pcmcia = {
     86 	2,	/* nslots */
     87 	dbau1550_slot_offset,
     88 	dbau1550_slot_irq,
     89 	dbau1550_slot_enable,
     90 	dbau1550_slot_disable,
     91 	dbau1550_slot_status,
     92 	dbau1550_slot_name,
     93 };
     94 
     95 static struct alchemy_board dbau1550_info = {
     96 	"AMD Alchemy DBAu1550",
     97 	dbau1550_devices,
     98 	dbau1550_init,
     99 	dbau1550_pci_intr_map,
    100 	dbau1550_reboot,
    101 	dbau1550_poweroff,
    102 	&dbau1550_pcmcia,
    103 };
    104 
    105 const struct alchemy_board *
    106 board_info(void)
    107 {
    108 
    109 	return &dbau1550_info;
    110 }
    111 
    112 void
    113 dbau1550_init(void)
    114 {
    115 	uint16_t		whoami;
    116 
    117 	if (MIPS_PRID_COPTS(cpu_id) != MIPS_AU1550)
    118 		panic("dbau1550: CPU not Au1550");
    119 
    120 	/* check the whoami register for a match */
    121 	whoami = GET16(DBAU1550_WHOAMI);
    122 
    123 	if (DBAU1550_WHOAMI_BOARD(whoami) != DBAU1550_WHOAMI_DBAU1550_REV1)
    124 		panic("dbau1550: WHOAMI (%x) not DBAu1550!", whoami);
    125 
    126 	printf("DBAu1550 (cabernet), CPLDv%d, ",
    127 	    DBAU1550_WHOAMI_CPLD(whoami));
    128 
    129 	if (DBAU1550_WHOAMI_DAUGHTER(whoami) != 0xf)
    130 		printf("daughtercard 0x%x\n",
    131 		    DBAU1550_WHOAMI_DAUGHTER(whoami));
    132 	else
    133 		printf("no daughtercard\n");
    134 
    135 	/* leave console and clocks alone -- YAMON should have got it right! */
    136 }
    137 
    138 int
    139 dbau1550_pci_intr_map(struct pci_attach_args *pa, pci_intr_handle_t *ihp)
    140 {
    141 	/*
    142 	 * This platform has one onboard PCI IDE controller, and two
    143 	 * PCI expansion slots.
    144 	 */
    145 	static const int irqmap[3/*device*/][4/*pin*/] = {
    146 		{  5, -1, -1, -1 },	/* 11: IDE */
    147 		{  2,  5,  6,  1 },	/* 12: PCI Slot 2 */
    148 		{  1,  2,  5,  6 },	/* 13: PCI Slot 3 */
    149 	};
    150 	int	pin, dev, irq;
    151 
    152 	/* if interrupt pin not used... */
    153 	if ((pin = pa->pa_intrpin) == 0)
    154 		return 1;
    155 
    156 	if (pin > 4) {
    157 		printf("pci: bad interrupt pin %d\n", pin);
    158 		return 1;
    159 	}
    160 
    161 	pci_decompose_tag(pa->pa_pc, pa->pa_intrtag, NULL, &dev, NULL);
    162 	if ((dev < 11) || (dev > 13)) {
    163 		printf("pci: bad device %d\n", dev);
    164 		return 1;
    165 	}
    166 
    167 	if ((irq = irqmap[dev - 11][pin - 1]) == -1) {
    168 		printf("pci: no IRQ routing for device %d pin %d\n", dev, pin);
    169 		return 1;
    170 	}
    171 
    172 	*ihp = irq;
    173 	return 0;
    174 }
    175 
    176 void
    177 dbau1550_reboot(void)
    178 {
    179 	PUT16(DBAU1550_SOFTWARE_RESET, 0);
    180 	wbflush();
    181 	delay(100000);	/* 100 msec */
    182 }
    183 
    184 void
    185 dbau1550_poweroff(void)
    186 {
    187 	printf("\n- poweroff -\n");
    188 	PUT16(DBAU1550_SOFTWARE_RESET,
    189 	    DBAU1550_SOFTWARE_RESET_PWROFF | DBAU1550_SOFTWARE_RESET_RESET);
    190 	wbflush();
    191 	delay(100000);	/* 100 msec */
    192 }
    193 
    194 int
    195 dbau1550_slot_irq(int slot, int which)
    196 {
    197 	static const int irqmap[2/*slot*/][2/*which*/] = {
    198 		{ 35, 32 },		/* Slot 0: Bottom */
    199 		{ 37, 33 },		/* Slot 1: Top */
    200 	};
    201 
    202 	if ((slot >= 2) || (which >= 2))
    203 		return -1;
    204 
    205 	return (irqmap[slot][which]);
    206 }
    207 
    208 bus_addr_t
    209 dbau1550_slot_offset(int slot)
    210 {
    211 	switch (slot) {
    212 	case 0:
    213 		return (DBAU1550_PC0_ADDR);
    214 	case 1:
    215 		return (DBAU1550_PC1_ADDR);
    216 	}
    217 
    218 	return (bus_addr_t)-1;
    219 }
    220 
    221 void
    222 dbau1550_slot_enable(int slot)
    223 {
    224 	uint16_t	status;
    225 	uint16_t	vcc, vpp;
    226 	int		shift;
    227 
    228 	status = GET16(DBAU1550_STATUS);
    229 	switch (slot) {
    230 	case 0:
    231 		status >>= DBAU1550_STATUS_PCMCIA0_VS_SHIFT;
    232 		shift = DBAU1550_PCMCIA_PC0_SHIFT;
    233 		break;
    234 	case 1:
    235 		status >>= DBAU1550_STATUS_PCMCIA1_VS_SHIFT;
    236 		shift = DBAU1550_PCMCIA_PC1_SHIFT;
    237 		break;
    238 	default:
    239 		return;
    240 	}
    241 
    242 	status &= DBAU1550_STATUS_PCMCIA_VS_MASK;
    243 	switch (status) {
    244 	case DBAU1550_STATUS_PCMCIA_VS_GND:
    245 		vcc = DBAU1550_PCMCIA_VCC_GND;
    246 		vpp = DBAU1550_PCMCIA_VPP_GND;
    247 		break;
    248 	case DBAU1550_STATUS_PCMCIA_VS_5V:
    249 		vcc = DBAU1550_PCMCIA_VCC_5V;
    250 		vpp = DBAU1550_PCMCIA_VPP_VCC;
    251 		break;
    252 	default:	/* covers both 3.3v cases */
    253 		vcc = DBAU1550_PCMCIA_VCC_3V;
    254 		vpp = DBAU1550_PCMCIA_VPP_VCC;
    255 		break;
    256 	}
    257 
    258 	status = GET16(DBAU1550_PCMCIA);
    259 
    260 	/* this clears all bits for this slot */
    261 	status &= ~(DBAU1550_PCMCIA_MASK << shift);
    262 
    263 	status |= vcc << shift;
    264 	status |= vpp << shift;
    265 
    266 	PUT16(DBAU1550_PCMCIA, status);
    267 	wbflush();
    268 	tsleep(&status, PWAIT, "pcmcia_reset_0", mstohz(100));
    269 
    270 	status |= (DBAU1550_PCMCIA_DRV_EN << shift);
    271 	PUT16(DBAU1550_PCMCIA, status);
    272 	wbflush();
    273 	tsleep(&status, PWAIT, "pcmcia_reset_start", mstohz(300));
    274 
    275 	/* take it out of reset */
    276 	status |= (DBAU1550_PCMCIA_RST << shift);
    277 	PUT16(DBAU1550_PCMCIA, status);
    278 	wbflush();
    279 
    280 	/* spec says 20 msec, but experience shows even 200 is not enough */
    281 	tsleep(&status, PWAIT, "pcmcia_reset_finish", mstohz(1000));
    282 
    283 	/* NOTE: WE DO NOT SUPPORT DIFFERENT VCC/VPP LEVELS! */
    284 	/* This means that 12V cards are not supported! */
    285 }
    286 
    287 void
    288 dbau1550_slot_disable(int slot)
    289 {
    290 	int		shift;
    291 	uint16_t	status;
    292 
    293 	switch (slot) {
    294 	case 0:
    295 		shift = DBAU1550_PCMCIA_PC0_SHIFT;
    296 		break;
    297 	case 1:
    298 		shift = DBAU1550_PCMCIA_PC1_SHIFT;
    299 		break;
    300 	}
    301 
    302 	status = GET16(DBAU1550_PCMCIA);
    303 	status &= ~(DBAU1550_PCMCIA_MASK);
    304 	PUT16(DBAU1550_PCMCIA, status);
    305 	wbflush();
    306 }
    307 
    308 int
    309 dbau1550_slot_status(int slot)
    310 {
    311 	uint16_t	status, mask;
    312 	status = GET16(DBAU1550_STATUS);
    313 	switch (slot) {
    314 	case 0:
    315 		mask = DBAU1550_STATUS_PCMCIA0_INSERTED;
    316 		break;
    317 	case 1:
    318 		mask = DBAU1550_STATUS_PCMCIA1_INSERTED;
    319 		break;
    320 
    321 	default:
    322 		return 0;
    323 	}
    324 
    325 	return ((mask & status) ? 0 : 1);
    326 }
    327 
    328 const char *
    329 dbau1550_slot_name(int slot)
    330 {
    331 	switch (slot) {
    332 	case 0:
    333 		return "bottom slot";
    334 	case 1:
    335 		return "top slot";
    336 	default:
    337 		return "???";
    338 	}
    339 }
    340