Home | History | Annotate | Line # | Download | only in altboot
pciide.c revision 1.11.4.1
      1  1.11.4.1       mrg /* $NetBSD: pciide.c,v 1.11.4.1 2012/02/18 07:33:05 mrg Exp $ */
      2       1.1  nisimura 
      3       1.1  nisimura /*-
      4       1.1  nisimura  * Copyright (c) 2008 The NetBSD Foundation, Inc.
      5       1.1  nisimura  * All rights reserved.
      6       1.1  nisimura  *
      7       1.1  nisimura  * This code is derived from software contributed to The NetBSD Foundation
      8       1.1  nisimura  * by Tohru Nishimura.
      9       1.1  nisimura  *
     10       1.1  nisimura  * Redistribution and use in source and binary forms, with or without
     11       1.1  nisimura  * modification, are permitted provided that the following conditions
     12       1.1  nisimura  * are met:
     13       1.1  nisimura  * 1. Redistributions of source code must retain the above copyright
     14       1.1  nisimura  *    notice, this list of conditions and the following disclaimer.
     15       1.1  nisimura  * 2. Redistributions in binary form must reproduce the above copyright
     16       1.1  nisimura  *    notice, this list of conditions and the following disclaimer in the
     17       1.1  nisimura  *    documentation and/or other materials provided with the distribution.
     18       1.1  nisimura  *
     19       1.1  nisimura  * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
     20       1.1  nisimura  * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
     21       1.1  nisimura  * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
     22       1.1  nisimura  * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
     23       1.1  nisimura  * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
     24       1.1  nisimura  * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
     25       1.1  nisimura  * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
     26       1.1  nisimura  * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
     27       1.1  nisimura  * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
     28       1.1  nisimura  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
     29       1.1  nisimura  * POSSIBILITY OF SUCH DAMAGE.
     30       1.1  nisimura  */
     31       1.1  nisimura 
     32       1.1  nisimura #include <sys/param.h>
     33       1.1  nisimura 
     34       1.1  nisimura #include <lib/libsa/stand.h>
     35       1.1  nisimura 
     36       1.1  nisimura #include "globals.h"
     37       1.1  nisimura 
     38      1.11       phx static void cmdidefix(struct dkdev_ata *);
     39      1.11       phx static void apoidefix(struct dkdev_ata *);
     40      1.11       phx static void iteidefix(struct dkdev_ata *);
     41       1.3       phx 
     42       1.1  nisimura static uint32_t pciiobase = PCI_XIOBASE;
     43       1.1  nisimura 
     44       1.1  nisimura struct myops {
     45      1.11       phx 	void (*chipfix)(struct dkdev_ata *);
     46       1.1  nisimura 	int (*presense)(struct dkdev_ata *, int);
     47       1.1  nisimura };
     48       1.3       phx static struct myops defaultops = { NULL, NULL };
     49       1.1  nisimura static struct myops cmdideops = { cmdidefix, NULL };
     50       1.8       phx static struct myops apoideops = { apoidefix, NULL };
     51      1.10       phx static struct myops iteideops = { iteidefix, NULL };
     52       1.2  nisimura static struct myops *myops;
     53       1.1  nisimura 
     54       1.1  nisimura int
     55       1.1  nisimura pciide_match(unsigned tag, void *data)
     56       1.1  nisimura {
     57       1.1  nisimura 	unsigned v;
     58       1.1  nisimura 
     59       1.1  nisimura 	v = pcicfgread(tag, PCI_ID_REG);
     60       1.1  nisimura 	switch (v) {
     61       1.1  nisimura 	case PCI_DEVICE(0x1095, 0x0680): /* SiI 0680 IDE */
     62       1.2  nisimura 		myops = &cmdideops;
     63       1.2  nisimura 		return 1;
     64       1.9  nisimura 	case PCI_DEVICE(0x1106, 0x0571): /* VIA 82C586A/B/686A/B IDE */
     65       1.8       phx 	case PCI_DEVICE(0x1106, 0x1571): /* VIA 82C586 IDE */
     66       1.8       phx 	case PCI_DEVICE(0x1106, 0x3164): /* VIA VT6410 RAID IDE */
     67       1.8       phx 		myops = &apoideops;
     68       1.8       phx 		return 1;
     69       1.1  nisimura 	case PCI_DEVICE(0x1283, 0x8211): /* ITE 8211 IDE */
     70      1.10       phx 		myops = &iteideops;
     71      1.10       phx 		return 1;
     72       1.1  nisimura 	case PCI_DEVICE(0x10ad, 0x0105): /* Symphony Labs 82C105 IDE */
     73       1.1  nisimura 	case PCI_DEVICE(0x10b8, 0x5229): /* ALi IDE */
     74       1.2  nisimura 	case PCI_DEVICE(0x1191, 0x0008): /* ACARD ATP865 */
     75       1.6       phx 	case PCI_DEVICE(0x1191, 0x0009): /* ACARD ATP865A */
     76       1.3       phx 		myops = &defaultops;
     77       1.1  nisimura 		return 1;
     78       1.1  nisimura 	}
     79       1.1  nisimura 	return 0;
     80       1.1  nisimura }
     81       1.1  nisimura 
     82       1.1  nisimura void *
     83       1.1  nisimura pciide_init(unsigned tag, void *data)
     84       1.1  nisimura {
     85  1.11.4.1       mrg 	static int cntrl = 0;
     86  1.11.4.1       mrg 	int native, n, retries;
     87       1.1  nisimura 	unsigned val;
     88       1.1  nisimura 	struct dkdev_ata *l;
     89       1.1  nisimura 
     90       1.1  nisimura 	l = alloc(sizeof(struct dkdev_ata));
     91       1.1  nisimura 	memset(l, 0, sizeof(struct dkdev_ata));
     92       1.1  nisimura 	l->iobuf = allocaligned(512, 16);
     93       1.1  nisimura 	l->tag = tag;
     94       1.1  nisimura 
     95       1.8       phx 	/* chipset specific fixes */
     96       1.8       phx 	if (myops->chipfix)
     97      1.11       phx 		(*myops->chipfix)(l);
     98       1.8       phx 
     99       1.1  nisimura 	val = pcicfgread(tag, PCI_CLASS_REG);
    100       1.5       phx 	native = PCI_CLASS(val) != PCI_CLASS_IDE ||
    101       1.5       phx 	    (PCI_INTERFACE(val) & 05) != 0;
    102       1.8       phx 
    103       1.1  nisimura 	if (native) {
    104       1.1  nisimura 		/* native, use BAR 01234 */
    105       1.1  nisimura 		l->bar[0] = pciiobase + (pcicfgread(tag, 0x10) &~ 01);
    106       1.1  nisimura 		l->bar[1] = pciiobase + (pcicfgread(tag, 0x14) &~ 01);
    107       1.1  nisimura 		l->bar[2] = pciiobase + (pcicfgread(tag, 0x18) &~ 01);
    108       1.1  nisimura 		l->bar[3] = pciiobase + (pcicfgread(tag, 0x1c) &~ 01);
    109       1.1  nisimura 		l->bar[4] = pciiobase + (pcicfgread(tag, 0x20) &~ 01);
    110       1.1  nisimura 		l->chan[0].cmd = l->bar[0];
    111       1.1  nisimura 		l->chan[0].ctl = l->chan[0].alt = l->bar[1] | 02;
    112       1.1  nisimura 		l->chan[0].dma = l->bar[4] + 0x0;
    113       1.1  nisimura 		l->chan[1].cmd = l->bar[2];
    114       1.1  nisimura 		l->chan[1].ctl = l->chan[1].alt = l->bar[3] | 02;
    115       1.1  nisimura 		l->chan[1].dma = l->bar[4] + 0x8;
    116       1.1  nisimura 	}
    117       1.1  nisimura 	else {
    118       1.1  nisimura 		/* legacy */
    119       1.1  nisimura 		l->bar[0]= pciiobase + 0x1f0;
    120       1.1  nisimura 		l->bar[1]= pciiobase + 0x3f4;
    121       1.1  nisimura 		l->bar[2]= pciiobase + 0x170;
    122       1.1  nisimura 		l->bar[3]= pciiobase + 0x374;
    123       1.1  nisimura 		l->chan[0].cmd = l->bar[0];
    124       1.1  nisimura 		l->chan[0].ctl = l->chan[0].alt = l->bar[1] | 02;
    125       1.1  nisimura 		l->chan[0].dma = 0;
    126       1.1  nisimura 		l->chan[1].cmd = l->bar[2];
    127       1.1  nisimura 		l->chan[1].ctl = l->chan[1].alt = l->bar[3] | 02;
    128       1.1  nisimura 		l->chan[1].dma = 0;
    129       1.1  nisimura 	}
    130       1.1  nisimura 
    131       1.1  nisimura 	for (n = 0; n < 2; n++) {
    132  1.11.4.1       mrg 		if (myops->presense != NULL && (*myops->presense)(l, n) == 0) {
    133  1.11.4.1       mrg 			DPRINTF(("channel %d not present\n", n));
    134  1.11.4.1       mrg 			l->presense[n] = 0;
    135  1.11.4.1       mrg 			continue;
    136  1.11.4.1       mrg 		} else if (get_drive_config(cntrl * 2 + n) == 0) {
    137  1.11.4.1       mrg 			DPRINTF(("channel %d disabled by config\n", n));
    138  1.11.4.1       mrg 			l->presense[n] = 0;
    139  1.11.4.1       mrg 			continue;
    140  1.11.4.1       mrg 		}
    141  1.11.4.1       mrg 
    142  1.11.4.1       mrg 		if (atachkpwr(l, n) != ATA_PWR_ACTIVE) {
    143  1.11.4.1       mrg 			/* drive is probably sleeping, wake it up */
    144  1.11.4.1       mrg 			for (retries = 0; retries < 10; retries++) {
    145  1.11.4.1       mrg 				wakeup_drive(l, n);
    146  1.11.4.1       mrg 				DPRINTF(("channel %d spinning up...\n", n));
    147  1.11.4.1       mrg 				delay(1000 * 1000);
    148  1.11.4.1       mrg 				l->presense[n] = perform_atareset(l, n);
    149  1.11.4.1       mrg 				if (atachkpwr(l, n) == ATA_PWR_ACTIVE)
    150  1.11.4.1       mrg 					break;
    151  1.11.4.1       mrg 			}
    152  1.11.4.1       mrg 		} else {
    153       1.1  nisimura 			/* check to see whether soft reset works */
    154  1.11.4.1       mrg 			DPRINTF(("channel %d active\n", n));
    155       1.1  nisimura 			l->presense[n] = perform_atareset(l, n);
    156  1.11.4.1       mrg 		}
    157      1.10       phx 
    158       1.1  nisimura 		if (l->presense[n])
    159       1.1  nisimura 			printf("channel %d present\n", n);
    160       1.1  nisimura 	}
    161       1.1  nisimura 
    162  1.11.4.1       mrg 	cntrl++;	/* increment controller number for next call */
    163       1.1  nisimura 	return l;
    164       1.1  nisimura }
    165       1.1  nisimura 
    166      1.11       phx static void
    167       1.1  nisimura cmdidefix(struct dkdev_ata *l)
    168       1.1  nisimura {
    169       1.8       phx 	unsigned v;
    170       1.1  nisimura 
    171       1.1  nisimura 	v = pcicfgread(l->tag, 0x80);
    172       1.1  nisimura 	pcicfgwrite(l->tag, 0x80, (v & ~0xff) | 0x01);
    173       1.1  nisimura 	v = pcicfgread(l->tag, 0x84);
    174       1.1  nisimura 	pcicfgwrite(l->tag, 0x84, (v & ~0xff) | 0x01);
    175       1.1  nisimura 	v = pcicfgread(l->tag, 0xa4);
    176       1.1  nisimura 	pcicfgwrite(l->tag, 0xa4, (v & ~0xffff) | 0x328a);
    177       1.1  nisimura 	v = pcicfgread(l->tag, 0xb4);
    178       1.1  nisimura 	pcicfgwrite(l->tag, 0xb4, (v & ~0xffff) | 0x328a);
    179       1.1  nisimura }
    180       1.8       phx 
    181      1.11       phx static void
    182       1.8       phx apoidefix(struct dkdev_ata *l)
    183       1.8       phx {
    184       1.8       phx 	unsigned v;
    185       1.8       phx 
    186       1.8       phx 	/* enable primary and secondary channel */
    187       1.8       phx 	v = pcicfgread(l->tag, 0x40) & ~0x03;
    188       1.8       phx 	pcicfgwrite(l->tag, 0x40, v | 0x03);
    189       1.8       phx }
    190      1.10       phx 
    191      1.11       phx static void
    192      1.10       phx iteidefix(struct dkdev_ata *l)
    193      1.10       phx {
    194      1.10       phx 	unsigned v;
    195      1.10       phx 
    196      1.10       phx 	/* set PCI mode and 66Mhz reference clock, disable IT8212 RAID */
    197      1.10       phx 	v = pcicfgread(l->tag, 0x50);
    198      1.10       phx 	pcicfgwrite(l->tag, 0x50, v & ~0x83);
    199      1.10       phx 
    200      1.10       phx 	/* i/o configuration, enable channels, cables, IORDY */
    201      1.10       phx 	v = pcicfgread(l->tag, 0x40);
    202      1.10       phx 	pcicfgwrite(l->tag, 0x40, (v & ~0xffffff) | 0x36a0f3);
    203      1.10       phx }
    204