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