xref: /netbsd-src/sys/dev/marvell/mvsata_mv.c (revision ba749f27a48cd1854d5310d7d71f03c36d865ad9)
1*ba749f27Skiyohara /*	$NetBSD: mvsata_mv.c,v 1.8 2017/01/07 14:24:27 kiyohara Exp $	*/
28406aeecSkiyohara /*
38406aeecSkiyohara  * Copyright (c) 2008 KIYOHARA Takashi
48406aeecSkiyohara  * All rights reserved.
58406aeecSkiyohara  *
68406aeecSkiyohara  * Redistribution and use in source and binary forms, with or without
78406aeecSkiyohara  * modification, are permitted provided that the following conditions
88406aeecSkiyohara  * are met:
98406aeecSkiyohara  * 1. Redistributions of source code must retain the above copyright
108406aeecSkiyohara  *    notice, this list of conditions and the following disclaimer.
118406aeecSkiyohara  * 2. Redistributions in binary form must reproduce the above copyright
128406aeecSkiyohara  *    notice, this list of conditions and the following disclaimer in the
138406aeecSkiyohara  *    documentation and/or other materials provided with the distribution.
148406aeecSkiyohara  *
158406aeecSkiyohara  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
168406aeecSkiyohara  * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
178406aeecSkiyohara  * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
188406aeecSkiyohara  * DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT,
198406aeecSkiyohara  * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
208406aeecSkiyohara  * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
218406aeecSkiyohara  * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
228406aeecSkiyohara  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
238406aeecSkiyohara  * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
248406aeecSkiyohara  * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
258406aeecSkiyohara  * POSSIBILITY OF SUCH DAMAGE.
268406aeecSkiyohara  */
278406aeecSkiyohara 
288406aeecSkiyohara #include <sys/cdefs.h>
29*ba749f27Skiyohara __KERNEL_RCSID(0, "$NetBSD: mvsata_mv.c,v 1.8 2017/01/07 14:24:27 kiyohara Exp $");
308406aeecSkiyohara 
318406aeecSkiyohara #include <sys/param.h>
328406aeecSkiyohara #include <sys/bus.h>
338406aeecSkiyohara #include <sys/device.h>
348406aeecSkiyohara #include <sys/errno.h>
358406aeecSkiyohara 
368406aeecSkiyohara #include <dev/ata/atareg.h>
378406aeecSkiyohara #include <dev/ata/atavar.h>
388406aeecSkiyohara #include <dev/ic/wdcvar.h>
398406aeecSkiyohara 
408406aeecSkiyohara #include <dev/ic/mvsatareg.h>
418406aeecSkiyohara #include <dev/ic/mvsatavar.h>
428406aeecSkiyohara 
438406aeecSkiyohara #include <dev/marvell/marvellreg.h>
448406aeecSkiyohara #include <dev/marvell/marvellvar.h>
458406aeecSkiyohara 
468406aeecSkiyohara #include "locators.h"
478406aeecSkiyohara 
488406aeecSkiyohara 
498406aeecSkiyohara #define MVSATAHC_SIZE			0x8000
508406aeecSkiyohara 
518406aeecSkiyohara #define MVSATAHC_NWINDOW		4
528406aeecSkiyohara 
538406aeecSkiyohara #define MVSATAHC_MICR			0x20 /* Main Interrupt Cause */
548406aeecSkiyohara #define MVSATAHC_MIMR			0x24 /* Main Interrupt Mask */
558406aeecSkiyohara #define MVSATAHC_MI_SATAERR(p)			(1 << ((p) * 2))
568406aeecSkiyohara #define MVSATAHC_MI_SATADONE(p)			(1 << (((p) * 2) + 1))
578406aeecSkiyohara #define MVSATAHC_MI_SATADMADONE(p)		(1 << ((p) + 4))
588406aeecSkiyohara #define MVSATAHC_MI_SATACOALDONE		(1 << 8)
598406aeecSkiyohara #define MVSATAHC_WCR(n)			(0x30 + (n) * 0x10) /* WinN Control */
608406aeecSkiyohara #define MVSATAHC_WCR_WINEN			(1 << 0)
618406aeecSkiyohara #define MVSATAHC_WCR_TARGET(t)			(((t) & 0xf) << 4)
628406aeecSkiyohara #define MVSATAHC_WCR_ATTR(a)			(((a) & 0xff) << 8)
638406aeecSkiyohara #define MVSATAHC_WCR_SIZE(s)			(((s) - 1) & 0xffff0000)
648406aeecSkiyohara #define MVSATAHC_WBR(n)			(0x34 + (n) * 0x10) /* WinN Base */
658406aeecSkiyohara #define MVSATAHC_WBR_BASE(b)			((b) & 0xffff0000)
668406aeecSkiyohara 
678406aeecSkiyohara 
688406aeecSkiyohara static int mvsatahc_match(device_t, cfdata_t, void *);
698406aeecSkiyohara static void mvsatahc_attach(device_t, device_t, void *);
708406aeecSkiyohara 
718406aeecSkiyohara static int mvsatahc_intr(void *);
728406aeecSkiyohara 
738406aeecSkiyohara static void mvsatahc_enable_intr(struct mvsata_port *, int);
74c51a6569Skiyohara static void mvsatahc_wininit(struct mvsata_softc *, enum marvell_tags *);
758406aeecSkiyohara 
768406aeecSkiyohara CFATTACH_DECL_NEW(mvsata_gt, sizeof(struct mvsata_softc),
778406aeecSkiyohara     mvsatahc_match, mvsatahc_attach, NULL, NULL);
788406aeecSkiyohara CFATTACH_DECL_NEW(mvsata_mbus, sizeof(struct mvsata_softc),
798406aeecSkiyohara     mvsatahc_match, mvsatahc_attach, NULL, NULL);
808406aeecSkiyohara 
818406aeecSkiyohara 
828406aeecSkiyohara struct mvsata_product mvsata_products[] = {
838406aeecSkiyohara #if 0
848406aeecSkiyohara 	/* Discovery VI */
858406aeecSkiyohara 	{ PCI_VENDOR_MARVELL, PCI_PRODUCT_MARVELL_MV64660, ?, ?, gen2?, 0 },
868406aeecSkiyohara #endif
878406aeecSkiyohara 
888406aeecSkiyohara 	/* Orion */
898406aeecSkiyohara 	{ PCI_VENDOR_MARVELL, PCI_PRODUCT_MARVELL_88F5082, 1, 1, gen2e, 0 },
908406aeecSkiyohara 	{ PCI_VENDOR_MARVELL, PCI_PRODUCT_MARVELL_88F5182, 1, 2, gen2e, 0 },
918406aeecSkiyohara 	{ PCI_VENDOR_MARVELL, PCI_PRODUCT_MARVELL_88F6082, 1, 1, gen2e, 0 },
928406aeecSkiyohara 
938406aeecSkiyohara 	/* Kirkwood */
948406aeecSkiyohara 	{ PCI_VENDOR_MARVELL, PCI_PRODUCT_MARVELL_88F6192, 1, 2, gen2e, 0 },
958406aeecSkiyohara 	{ PCI_VENDOR_MARVELL, PCI_PRODUCT_MARVELL_88F6281, 1, 2, gen2e, 0 },
961a7ac6e4Skiyohara 	{ PCI_VENDOR_MARVELL, PCI_PRODUCT_MARVELL_88F6282, 1, 2, gen2e, 0 },
978406aeecSkiyohara 
987e0b1251Skiyohara 	/* Discovery Innovation */
998406aeecSkiyohara 	{ PCI_VENDOR_MARVELL, PCI_PRODUCT_MARVELL_MV78100, 1, 2, gen2e, 0 },
1007e0b1251Skiyohara 	{ PCI_VENDOR_MARVELL, PCI_PRODUCT_MARVELL_MV78200, 1, 2, gen2e, 0 },
101055ac78aSrkujawa 
102*ba749f27Skiyohara 	/* Dove */
103*ba749f27Skiyohara 	{ PCI_VENDOR_MARVELL, PCI_PRODUCT_MARVELL_88AP510, 1, 1, gen2e, 0 },
104*ba749f27Skiyohara 
105055ac78aSrkujawa 	/* Armada XP */
1065c651e5bSkiyohara 	{ PCI_VENDOR_MARVELL, PCI_PRODUCT_MARVELL_MV78130, 1, 2, gen2e, 0 },
1075c651e5bSkiyohara 	{ PCI_VENDOR_MARVELL, PCI_PRODUCT_MARVELL_MV78160, 1, 2, gen2e, 0 },
1085c651e5bSkiyohara 	{ PCI_VENDOR_MARVELL, PCI_PRODUCT_MARVELL_MV78230, 1, 2, gen2e, 0 },
1095c651e5bSkiyohara 	{ PCI_VENDOR_MARVELL, PCI_PRODUCT_MARVELL_MV78260, 1, 2, gen2e, 0 },
110055ac78aSrkujawa 	{ PCI_VENDOR_MARVELL, PCI_PRODUCT_MARVELL_MV78460, 1, 2, gen2e, 0 },
111c51a6569Skiyohara 
112c51a6569Skiyohara 	/* Armada 370 */
113c51a6569Skiyohara 	{ PCI_VENDOR_MARVELL, PCI_PRODUCT_MARVELL_MV6707, 1, 2, gen2e, 0 },
114c51a6569Skiyohara 	{ PCI_VENDOR_MARVELL, PCI_PRODUCT_MARVELL_MV6710, 1, 2, gen2e, 0 },
115c51a6569Skiyohara 	{ PCI_VENDOR_MARVELL, PCI_PRODUCT_MARVELL_MV6W11, 1, 2, gen2e, 0 },
1168406aeecSkiyohara };
1178406aeecSkiyohara 
1188406aeecSkiyohara 
1198406aeecSkiyohara /* ARGSUSED */
1208406aeecSkiyohara static int
mvsatahc_match(device_t parent,cfdata_t match,void * aux)1218406aeecSkiyohara mvsatahc_match(device_t parent, cfdata_t match, void *aux)
1228406aeecSkiyohara {
1238406aeecSkiyohara 	struct marvell_attach_args *mva = aux;
1248406aeecSkiyohara 	int i;
1258406aeecSkiyohara 
126049fc261Skiyohara 	if (strcmp(mva->mva_name, match->cf_name) != 0)
127049fc261Skiyohara 		return 0;
1288406aeecSkiyohara 	if (mva->mva_offset == MVA_OFFSET_DEFAULT ||
1298406aeecSkiyohara 	    mva->mva_irq == MVA_IRQ_DEFAULT)
1308406aeecSkiyohara 		    return 0;
1318406aeecSkiyohara 
1328406aeecSkiyohara 	for (i = 0; i < __arraycount(mvsata_products); i++)
1338406aeecSkiyohara 		if (mva->mva_model == mvsata_products[i].model) {
1348406aeecSkiyohara 			mva->mva_size = MVSATAHC_SIZE;
1358406aeecSkiyohara 			return 1;
1368406aeecSkiyohara 		}
1378406aeecSkiyohara 	return 0;
1388406aeecSkiyohara }
1398406aeecSkiyohara 
1408406aeecSkiyohara /* ARGSUSED */
1418406aeecSkiyohara static void
mvsatahc_attach(device_t parent,device_t self,void * aux)1428406aeecSkiyohara mvsatahc_attach(device_t parent, device_t self, void *aux)
1438406aeecSkiyohara {
1448406aeecSkiyohara 	struct mvsata_softc *sc = device_private(self);
1458406aeecSkiyohara 	struct marvell_attach_args *mva = aux;
1468406aeecSkiyohara 	uint32_t mask;
1478406aeecSkiyohara 	int port, i;
1488406aeecSkiyohara 
1498406aeecSkiyohara 	aprint_normal(": Marvell Serial-ATA Host Controller (SATAHC)\n");
1508406aeecSkiyohara 	aprint_naive("\n");
1518406aeecSkiyohara 
1528406aeecSkiyohara 	sc->sc_wdcdev.sc_atac.atac_dev = self;
1538406aeecSkiyohara 	sc->sc_model = mva->mva_model;
1548406aeecSkiyohara 	sc->sc_iot = mva->mva_iot;
1558406aeecSkiyohara         if (bus_space_subregion(mva->mva_iot, mva->mva_ioh, mva->mva_offset,
1568406aeecSkiyohara 	    mva->mva_size, &sc->sc_ioh)) {
1578406aeecSkiyohara 		aprint_error_dev(self, "can't map registers\n");
1588406aeecSkiyohara 		return;
1598406aeecSkiyohara 	}
1608406aeecSkiyohara 	sc->sc_dmat = mva->mva_dmat;
1618406aeecSkiyohara 	sc->sc_enable_intr = mvsatahc_enable_intr;
1628406aeecSkiyohara 
163c51a6569Skiyohara 	mvsatahc_wininit(sc, mva->mva_tags);
1648406aeecSkiyohara 
1658406aeecSkiyohara 	for (i = 0; i < __arraycount(mvsata_products); i++)
1668406aeecSkiyohara 		if (mva->mva_model == mvsata_products[i].model)
1678406aeecSkiyohara 			break;
1688406aeecSkiyohara 	KASSERT(i < __arraycount(mvsata_products));
1698406aeecSkiyohara 
1708406aeecSkiyohara 	if (mvsata_attach(sc, &mvsata_products[i], NULL, NULL, 0) != 0)
1718406aeecSkiyohara 		return;
1728406aeecSkiyohara 
1738406aeecSkiyohara 	marvell_intr_establish(mva->mva_irq, IPL_BIO, mvsatahc_intr, sc);
1748406aeecSkiyohara 	mask = 0;
1758406aeecSkiyohara 	for (port = 0; port < sc->sc_port; port++)
1768406aeecSkiyohara 		mask |=
1778406aeecSkiyohara 		    MVSATAHC_MI_SATAERR(port) |
1788406aeecSkiyohara 		    MVSATAHC_MI_SATADONE(port);
1798406aeecSkiyohara 	bus_space_write_4(sc->sc_iot, sc->sc_ioh, MVSATAHC_MIMR, mask);
1808406aeecSkiyohara }
1818406aeecSkiyohara 
1828406aeecSkiyohara static int
mvsatahc_intr(void * arg)1838406aeecSkiyohara mvsatahc_intr(void *arg)
1848406aeecSkiyohara {
1858406aeecSkiyohara 	struct mvsata_softc *sc = (struct mvsata_softc *)arg;
1868406aeecSkiyohara 	struct mvsata_hc *mvhc = &sc->sc_hcs[0];
1878406aeecSkiyohara 	uint32_t cause, handled = 0;
1888406aeecSkiyohara 
1898406aeecSkiyohara 	cause = bus_space_read_4(sc->sc_iot, sc->sc_ioh, MVSATAHC_MICR);
1908406aeecSkiyohara 	if (cause & MVSATAHC_MI_SATAERR(0))
1918406aeecSkiyohara 		handled |= mvsata_error(mvhc->hc_ports[0]);
1928406aeecSkiyohara 	if (cause & MVSATAHC_MI_SATAERR(1))
1938406aeecSkiyohara 		handled |= mvsata_error(mvhc->hc_ports[1]);
1948406aeecSkiyohara 	if (cause & (MVSATAHC_MI_SATADONE(0) | MVSATAHC_MI_SATADONE(1)))
1958406aeecSkiyohara 		handled |= mvsata_intr(mvhc);
1968406aeecSkiyohara 
1978406aeecSkiyohara 	return handled;
1988406aeecSkiyohara }
1998406aeecSkiyohara 
2008406aeecSkiyohara 
2018406aeecSkiyohara static void
mvsatahc_enable_intr(struct mvsata_port * mvport,int on)2028406aeecSkiyohara mvsatahc_enable_intr(struct mvsata_port *mvport, int on)
2038406aeecSkiyohara {
2048406aeecSkiyohara 	struct mvsata_softc *sc =
2058406aeecSkiyohara 	    device_private(mvport->port_ata_channel.ch_atac->atac_dev);
2068406aeecSkiyohara 	uint32_t mask;
2078406aeecSkiyohara 
2088406aeecSkiyohara 	mask = bus_space_read_4(sc->sc_iot, sc->sc_ioh, MVSATAHC_MIMR);
2098406aeecSkiyohara 	if (on)
2108406aeecSkiyohara 		mask |= MVSATAHC_MI_SATADONE(mvport->port);
2118406aeecSkiyohara 	else
2128406aeecSkiyohara 		mask &= ~MVSATAHC_MI_SATADONE(mvport->port);
2138406aeecSkiyohara 	bus_space_write_4(sc->sc_iot, sc->sc_ioh, MVSATAHC_MIMR, mask);
2148406aeecSkiyohara }
2158406aeecSkiyohara 
2168406aeecSkiyohara static void
mvsatahc_wininit(struct mvsata_softc * sc,enum marvell_tags * tags)217c51a6569Skiyohara mvsatahc_wininit(struct mvsata_softc *sc, enum marvell_tags *tags)
2188406aeecSkiyohara {
2198406aeecSkiyohara 	device_t pdev = device_parent(sc->sc_wdcdev.sc_atac.atac_dev);
2208406aeecSkiyohara 	uint64_t base;
2218406aeecSkiyohara 	uint32_t size;
2228406aeecSkiyohara 	int window, target, attr, rv, i;
2238406aeecSkiyohara 
2248406aeecSkiyohara 	for (window = 0, i = 0;
2258406aeecSkiyohara 	    tags[i] != MARVELL_TAG_UNDEFINED && window < MVSATAHC_NWINDOW;
2268406aeecSkiyohara 	    i++) {
2278406aeecSkiyohara 		rv = marvell_winparams_by_tag(pdev, tags[i],
2288406aeecSkiyohara 		    &target, &attr, &base, &size);
2298406aeecSkiyohara 		if (rv != 0 || size == 0)
2308406aeecSkiyohara 			continue;
2318406aeecSkiyohara 		if (base > 0xffffffffULL) {
2328406aeecSkiyohara 			aprint_error_dev(sc->sc_wdcdev.sc_atac.atac_dev,
2338406aeecSkiyohara 			    "tag %d address 0x%llx not support\n",
2348406aeecSkiyohara 			    tags[i], base);
2358406aeecSkiyohara 			continue;
2368406aeecSkiyohara 		}
2378406aeecSkiyohara 
2388406aeecSkiyohara 		bus_space_write_4(sc->sc_iot, sc->sc_ioh,
2398406aeecSkiyohara 		    MVSATAHC_WCR(window),
2408406aeecSkiyohara 		    MVSATAHC_WCR_WINEN |
2418406aeecSkiyohara 		    MVSATAHC_WCR_TARGET(target) |
2428406aeecSkiyohara 		    MVSATAHC_WCR_ATTR(attr) |
2438406aeecSkiyohara 		    MVSATAHC_WCR_SIZE(size));
2448406aeecSkiyohara 		bus_space_write_4(sc->sc_iot, sc->sc_ioh,
2458406aeecSkiyohara 		    MVSATAHC_WBR(window), MVSATAHC_WBR_BASE(base));
2468406aeecSkiyohara 		window++;
2478406aeecSkiyohara 	}
2488406aeecSkiyohara 	for (; window < MVSATAHC_NWINDOW; window++)
2498406aeecSkiyohara 		bus_space_write_4(sc->sc_iot, sc->sc_ioh,
2508406aeecSkiyohara 		    MVSATAHC_WCR(window), 0);
2518406aeecSkiyohara }
252