NetBSD-Bugs archive

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index][Old Index]

Re: kern/53716: PCengines APU2 requires AHCI enabler



I re-worked the patch as following:

Index: sys/dev/ic/ahcisatavar.h
===================================================================
RCS file: /export/cvsroot/netbsd/src/sys/dev/ic/ahcisatavar.h,v
retrieving revision 1.17
diff -u -r1.17 ahcisatavar.h
--- sys/dev/ic/ahcisatavar.h	24 May 2015 22:30:05 -0000	1.17
+++ sys/dev/ic/ahcisatavar.h	11 Nov 2018 05:30:32 -0000
@@ -60,6 +60,7 @@
 #define AHCI_QUIRK_BADPMP	__BIT(2)  /* broken PMP support, ignore */
 #define AHCI_QUIRK_BADPMPRESET	__BIT(3)  /* broken PMP support for reset */
 #define AHCI_QUIRK_SKIP_RESET	__BIT(4)  /* skip drive reset sequence */
+#define AHCI_PCI_QUIRK_FIXUP	__BIT(5)  /* interface needs fixup */
 
 	uint32_t sc_ahci_cap;	/* copy of AHCI_CAP */
 	int sc_ncmds; /* number of command slots */
Index: sys/dev/pci/ahcisata_pci.c
===================================================================
RCS file: /export/cvsroot/netbsd/src/sys/dev/pci/ahcisata_pci.c,v
retrieving revision 1.38
diff -u -r1.38 ahcisata_pci.c
--- sys/dev/pci/ahcisata_pci.c	13 Oct 2016 17:11:09 -0000	1.38
+++ sys/dev/pci/ahcisata_pci.c	11 Nov 2018 10:57:34 -0000
@@ -194,6 +194,8 @@
 	    AHCI_PCI_QUIRK_FORCE },
 	{ PCI_VENDOR_ASMEDIA, PCI_PRODUCT_ASMEDIA_ASM1061_12,
 	    AHCI_PCI_QUIRK_FORCE },
+	{ PCI_VENDOR_AMD, PCI_PRODUCT_AMD_HUDSON_SATA,
+	    AHCI_PCI_QUIRK_FORCE | AHCI_PCI_QUIRK_FIXUP },
 };
 
 struct ahci_pci_softc {
@@ -208,7 +210,7 @@
 static void ahci_pci_attach(device_t, device_t, void *);
 static int  ahci_pci_detach(device_t, int);
 static bool ahci_pci_resume(device_t, const pmf_qual_t *);
-
+static void ahci_pci_fixup_interface(device_t);
 
 CFATTACH_DECL_NEW(ahcisata_pci, sizeof(struct ahci_pci_softc),
     ahci_pci_match, ahci_pci_attach, ahci_pci_detach, NULL);
@@ -273,7 +275,17 @@
 	pci_intr_handle_t intrhandle;
 	char intrbuf[PCI_INTRSTR_LEN];
 
+	pci_aprint_devinfo(pa, "AHCI disk controller");
+	
 	sc->sc_atac.atac_dev = self;
+	sc->sc_ahci_quirks = ahci_pci_has_quirk(PCI_VENDOR(pa->pa_id),
+					    PCI_PRODUCT(pa->pa_id));
+
+	psc->sc_pc = pa->pa_pc;
+	psc->sc_pcitag = pa->pa_tag;
+
+	if (sc->sc_ahci_quirks & AHCI_PCI_QUIRK_FIXUP)
+		ahci_pci_fixup_interface(self);
 
 	if (pci_mapreg_map(pa, AHCI_PCI_ABAR,
 	    PCI_MAPREG_TYPE_MEM | PCI_MAPREG_MEM_TYPE_32BIT, 0,
@@ -281,11 +293,7 @@
 		aprint_error_dev(self, "can't map ahci registers\n");
 		return;
 	}
-	psc->sc_pc = pa->pa_pc;
-	psc->sc_pcitag = pa->pa_tag;
 
-	pci_aprint_devinfo(pa, "AHCI disk controller");
-	
 	if (pci_intr_map(pa, &intrhandle) != 0) {
 		aprint_error_dev(self, "couldn't map interrupt\n");
 		return;
@@ -302,8 +310,6 @@
 
 	sc->sc_dmat = pa->pa_dmat;
 
-	sc->sc_ahci_quirks = ahci_pci_has_quirk(PCI_VENDOR(pa->pa_id),
-					    PCI_PRODUCT(pa->pa_id));
 
 	ahci_cap_64bit = (AHCI_READ(sc, AHCI_CAP) & AHCI_CAP_64BIT) != 0;
 	ahci_bad_64bit = ((sc->sc_ahci_quirks & AHCI_PCI_QUIRK_BAD64) != 0);
@@ -364,3 +370,58 @@
 
 	return true;
 }
+
+/*
+ * Switch devices in legacy IDE interface to native AHCI, if desired.
+ *
+ * In some devices, especially in PCengines APU2 series, the BIOS left
+ * AHCI devices in IDE/legacy mode to simplify their code and some
+ * unknown compatibility reasons.  Since we have no PCI-IDE DMA
+ * handler for the AMD Hudson SATA IDE controller, we should re-program
+ * interfacing mode and use it in native AHCI.
+ *
+ * see ftp://kolibrios.org/users/art_zh/doc/public/A50_RPR.pdf
+ * for register programming details.
+ */
+static void
+ahci_pci_fixup_interface(device_t dv)
+{
+	struct ahci_pci_softc *psc = device_private(dv);
+	int cc;
+	int reg;
+
+	/*
+	 * check the interface mode in IDE/legacy
+	 */
+	cc = pci_conf_read(psc->sc_pc, psc->sc_pcitag, 0x08);
+	if (!(PCI_CLASS(cc) == PCI_CLASS_MASS_STORAGE &&
+	    PCI_SUBCLASS(cc) == PCI_SUBCLASS_MASS_STORAGE_IDE))
+		return;
+
+	aprint_normal_dev(dv, "switch legacy IDE to native AHCI\n");
+
+	/*
+	 * make subclass/interface register is writeable.
+	 */
+	reg = pci_conf_read(psc->sc_pc, psc->sc_pcitag, 0x40);
+	reg |= 1;
+	pci_conf_write(psc->sc_pc, psc->sc_pcitag, 0x40, reg);
+
+	/*
+	 * rewrite subclass/interface register.
+	 * this causes switch interface logic.
+	 */
+	reg = pci_conf_read(psc->sc_pc, psc->sc_pcitag, PCI_CLASS_REG);
+	reg &= ~PCI_SUBCLASS(PCI_SUBCLASS_MASK);
+	reg |=  PCI_SUBCLASS(PCI_SUBCLASS_MASS_STORAGE_SATA);
+	reg &= ~PCI_INTERFACE(PCI_INTERFACE_MASK);
+	reg |=  PCI_INTERFACE(PCI_INTERFACE_SATA_AHCI);
+	pci_conf_write(psc->sc_pc, psc->sc_pcitag, PCI_CLASS_REG, reg);
+
+	/*
+	 * make subclass/interface register is read-only.
+	 */
+	reg = pci_conf_read(psc->sc_pc, psc->sc_pcitag, 0x40);
+	reg &= ~1;
+	pci_conf_write(psc->sc_pc, psc->sc_pcitag, 0x40, reg);
+}


-- 
Shinichi Doyashiki <clare%csel.org@localhost>


Home | Main Index | Thread Index | Old Index