Home | History | Annotate | Line # | Download | only in alchemy
dbau1550.c revision 1.5
      1 /* $NetBSD: dbau1550.c,v 1.5 2006/02/23 03:51:40 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.5 2006/02/23 03:51:40 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 	printf("enable slot %d\n", slot);
    229 
    230 	status = GET16(DBAU1550_STATUS);
    231 	switch (slot) {
    232 	case 0:
    233 		status >>= DBAU1550_STATUS_PCMCIA0_VS_SHIFT;
    234 		shift = DBAU1550_PCMCIA_PC0_SHIFT;
    235 		break;
    236 	case 1:
    237 		status >>= DBAU1550_STATUS_PCMCIA1_VS_SHIFT;
    238 		shift = DBAU1550_PCMCIA_PC1_SHIFT;
    239 		break;
    240 	default:
    241 		return;
    242 	}
    243 
    244 	status &= DBAU1550_STATUS_PCMCIA_VS_MASK;
    245 	switch (status) {
    246 	case DBAU1550_STATUS_PCMCIA_VS_GND:
    247 		vcc = DBAU1550_PCMCIA_VCC_GND;
    248 		vpp = DBAU1550_PCMCIA_VPP_GND;
    249 		printf("enable slot %d GND\n", slot);
    250 		break;
    251 	case DBAU1550_STATUS_PCMCIA_VS_5V:
    252 		vcc = DBAU1550_PCMCIA_VCC_5V;
    253 		vpp = DBAU1550_PCMCIA_VPP_VCC;
    254 		printf("enable slot %d 5V\n", slot);
    255 		break;
    256 	default:	/* covers both 3.3v cases */
    257 		printf("enable slot %d 3.3V\n", slot);
    258 		vcc = DBAU1550_PCMCIA_VCC_3V;
    259 		vpp = DBAU1550_PCMCIA_VPP_VCC;
    260 		break;
    261 	}
    262 
    263 	status = GET16(DBAU1550_PCMCIA);
    264 
    265 	/* this clears all bits for this slot */
    266 	status &= ~(DBAU1550_PCMCIA_MASK << shift);
    267 
    268 	status |= vcc << shift;
    269 	status |= vpp << shift;
    270 
    271 	PUT16(DBAU1550_PCMCIA, status);
    272 	wbflush();
    273 	tsleep(&status, PWAIT, "pcmcia_reset_0", mstohz(100));
    274 
    275 	status |= (DBAU1550_PCMCIA_DRV_EN << shift);
    276 	PUT16(DBAU1550_PCMCIA, status);
    277 	wbflush();
    278 	tsleep(&status, PWAIT, "pcmcia_reset_start", mstohz(300));
    279 
    280 	/* take it out of reset */
    281 	status |= (DBAU1550_PCMCIA_RST << shift);
    282 	PUT16(DBAU1550_PCMCIA, status);
    283 	wbflush();
    284 	tsleep(&status, PWAIT, "pcmcia_reset_finish", mstohz(100));
    285 
    286 	/* NOTE: WE DO NOT SUPPORT DIFFERENT VCC/VPP LEVELS! */
    287 	/* This means that 12V cards are not supported! */
    288 	printf("enable slot %d done\n", slot);
    289 }
    290 
    291 void
    292 dbau1550_slot_disable(int slot)
    293 {
    294 	int		shift;
    295 	uint16_t	status;
    296 
    297 	printf("disable slot %d\n", slot);
    298 	switch (slot) {
    299 	case 0:
    300 		shift = DBAU1550_PCMCIA_PC0_SHIFT;
    301 		break;
    302 	case 1:
    303 		shift = DBAU1550_PCMCIA_PC1_SHIFT;
    304 		break;
    305 	}
    306 
    307 	status = GET16(DBAU1550_PCMCIA);
    308 	status &= ~(DBAU1550_PCMCIA_MASK);
    309 	PUT16(DBAU1550_PCMCIA, status);
    310 	wbflush();
    311 	printf("disable slot %d done\n", slot);
    312 }
    313 
    314 int
    315 dbau1550_slot_status(int slot)
    316 {
    317 	uint16_t	status, mask;
    318 	status = GET16(DBAU1550_STATUS);
    319 	switch (slot) {
    320 	case 0:
    321 		mask = DBAU1550_STATUS_PCMCIA0_INSERTED;
    322 		break;
    323 	case 1:
    324 		mask = DBAU1550_STATUS_PCMCIA1_INSERTED;
    325 		break;
    326 
    327 	default:
    328 		return 0;
    329 	}
    330 
    331 	return ((mask & status) ? 0 : 1);
    332 }
    333 
    334 const char *
    335 dbau1550_slot_name(int slot)
    336 {
    337 	switch (slot) {
    338 	case 0:
    339 		return "bottom slot";
    340 	case 1:
    341 		return "top slot";
    342 	default:
    343 		return "???";
    344 	}
    345 }
    346