Booting Imac G5

Benjamin Herrenschmidt benh at kernel.crashing.org
Sun Nov 7 11:32:48 EST 2004


On Sun, 2004-11-07 at 10:51 +1100, Benjamin Herrenschmidt wrote:
> Ok, a new Darwin is out and the driver there has some additional bits,
> related to the SATA cell. I'm hacking together a patch.

Index: linux-work/drivers/scsi/sata_svw.c
===================================================================
--- linux-work.orig/drivers/scsi/sata_svw.c	2004-10-13 09:02:05.000000000 +1000
+++ linux-work/drivers/scsi/sata_svw.c	2004-11-07 11:23:41.945588808 +1100
@@ -49,7 +49,7 @@
 #endif /* CONFIG_PPC_OF */
 
 #define DRV_NAME	"sata_svw"
-#define DRV_VERSION	"1.04"
+#define DRV_VERSION	"1.05"
 
 /* Taskfile registers offsets */
 #define K2_SATA_TF_CMD_OFFSET		0x00
@@ -75,10 +75,19 @@
 #define K2_SATA_SICR1_OFFSET		0x80
 #define K2_SATA_SICR2_OFFSET		0x84
 #define K2_SATA_SIM_OFFSET		0x88
+#define K2_SATA_MDIO_ACCESS		0x8c
 
 /* Port stride */
 #define K2_SATA_PORT_OFFSET		0x100
 
+/* Private structure */
+struct k2_sata_priv
+{
+#ifdef CONFIG_PPC_OF
+	struct device_node *of_node;
+#endif
+	int need_mdio_phy_reset;
+};
 
 static u32 k2_sata_scr_read (struct ata_port *ap, unsigned int sc_reg)
 {
@@ -96,6 +105,42 @@
 	writel(val, (void *) ap->ioaddr.scr_addr + (sc_reg * 4));
 }
 
+static u16 k2_sata_mdio_read(struct ata_host_set *host, int reg)
+{
+	u16 val;
+	int timeout;
+
+	writel(host_set->mmio_base + K2_SATA_MDIO_ACCESS,
+	       (reg & 0x1f) | 0x4000);
+	for(timeout = 10000; timeout > 0; timeout++) {
+		val = readl(host_set->mmio_base + K2_SATA_MDIO_ACCESS);
+		if (val & 0x8000)
+			break;
+		udelay(100);
+	}
+	if (timeout <= 0) {
+		printk(KERN_WARNING "sata_svw: timeout reading MDIO reg %d\n", reg);
+		return 0xffff;
+	}
+	return val >> 16;
+}
+
+static void k2_sata_mdio_write(struct ata_host_set *host, int reg, u16 val)
+{
+	u16 val;
+	int timeout;
+
+	writel(host_set->mmio_base + K2_SATA_MDIO_ACCESS,
+	       (reg & 0x1f) | (((u32)val) << 16) | 0x2000);
+	for(timeout = 10000; timeout > 0; timeout++) {
+		val = readl(host_set->mmio_base + K2_SATA_MDIO_ACCESS);
+		if (val & 0x8000)
+			break;
+		udelay(100);
+	}
+	if (timeout <= 0)
+		printk(KERN_WARNING "sata_svw: timeout writing MDIO reg %d\n", reg);
+}
 
 static void k2_sata_tf_load(struct ata_port *ap, struct ata_taskfile *tf)
 {
@@ -220,6 +265,31 @@
        	return readl((void *) ap->ioaddr.status_addr);
 }
 
+static void k2_sata_mdio_phy_reset(struct ata_host_set *host_set);
+{
+	u16 reg;
+
+	reg = k2_sata_mdio_read(host_set, 4);
+	k2_sata_mdio_write(host_set, 4, reg | 0x0008);
+	udelay(200);
+	k2_sata_mdio_write(host_set, 4, reg);
+	udelay(250);
+}
+
+static void k2_sata_host_start(struct ata_host_set *host_set)
+{
+	struct k2_sata_priv *pp;
+
+	pp = host_set->private_data;
+
+	/* Some cell revs need a HW reset of the PHY layer at this point, and
+	 * on wakeup from power management
+	 */
+	if (pp->need_mdio_phy_reset)
+		k2_sata_mdio_phy_reset(host_set);
+}
+
+
 #ifdef CONFIG_PPC_OF
 /*
  * k2_sata_proc_info
@@ -237,15 +307,15 @@
 {
 	struct ata_port *ap;
 	struct device_node *np;
+	struct k2_sata_priv *pp;
 	int len, index;
 
 	/* Find  the ata_port */
 	ap = (struct ata_port *) &shost->hostdata[0];
 	if (ap == NULL)
 		return 0;
-
-	/* Find the OF node for the PCI device proper */
-	np = pci_device_to_OF_node(ap->host_set->pdev);
+	pp = ap->host_set->private_data;
+	np = pp->of_node;
 	if (np == NULL)
 		return 0;
 
@@ -310,6 +380,7 @@
 	.scr_write		= k2_sata_scr_write,
 	.port_start		= ata_port_start,
 	.port_stop		= ata_port_stop,
+	.host_start		= k2_sata_host_start,
 };
 
 static void k2_sata_setup_port(struct ata_ioports *port, unsigned long base)
@@ -338,6 +409,7 @@
 	struct ata_probe_ent *probe_ent = NULL;
 	unsigned long base;
 	void *mmio_base;
+	struct k2_sata_priv *pp = NULL;
 	int rc;
 
 	if (!printed_version++)
@@ -374,10 +446,31 @@
 		rc = -ENOMEM;
 		goto err_out_regions;
 	}
-
 	memset(probe_ent, 0, sizeof(*probe_ent));
+
+	pp = (struct k2_sata_priv *)kmalloc(sizeof(struct k2_sata_priv), GFP_KERNEL);
+	if (pp == NULL) {
+		rc = -ENOMEM;
+		goto err_out_free_ent;
+	}
+	memset(pp, 0, sizeof(struct k2_sata_priv));
+
 	probe_ent->pdev = pdev;
 	INIT_LIST_HEAD(&probe_ent->node);
+	probe_ent->private_data = pdev;
+
+#ifdef CONFIG_PPC_OF
+	/* Find the OF node for the PCI device proper */
+	pp->of_node = pci_device_to_OF_node(ap->host_set->pdev);
+
+	/* Check for revision 1 */
+	if (pp->of_node) {
+		u32 *rev;
+		rev = (u32 *)get_property(pp->of_node, "cell-revision", NULL);
+		if (rev && (*rev) > 0)
+			pp->need_mdio_phy_reset = 1;
+	}
+#endif /* CONFIG_PPC_OF */
 
 	mmio_base = ioremap(pci_resource_start(pdev, 5),
 		            pci_resource_len(pdev, 5));
@@ -429,7 +522,10 @@
 	return 0;
 
 err_out_free_ent:
-	kfree(probe_ent);
+	if (pp)
+		kfree(pp);
+	if (probe_ent)
+		kfree(probe_ent);
 err_out_regions:
 	pci_release_regions(pdev);
 err_out:
Index: linux-work/drivers/scsi/libata-core.c
===================================================================
--- linux-work.orig/drivers/scsi/libata-core.c	2004-11-07 11:24:09.617382056 +1100
+++ linux-work/drivers/scsi/libata-core.c	2004-11-07 11:24:40.491688448 +1100
@@ -3271,6 +3271,9 @@
 	host_set->private_data = ent->private_data;
 	host_set->ops = ent->port_ops;
 
+	if (host_set->ops->host_start)
+		host_set->ops->host_start(host_set);
+
 	/* register each port bound to this device */
 	for (i = 0; i < ent->n_ports; i++) {
 		struct ata_port *ap;
Index: linux-work/include/linux/libata.h
===================================================================
--- linux-work.orig/include/linux/libata.h	2004-11-07 11:23:56.598361248 +1100
+++ linux-work/include/linux/libata.h	2004-11-07 11:24:54.242597992 +1100
@@ -349,6 +349,7 @@
 	int (*port_start) (struct ata_port *ap);
 	void (*port_stop) (struct ata_port *ap);
 
+	void (*host_start) (struct ata_host_set *host_set);
 	void (*host_stop) (struct ata_host_set *host_set);
 };
 





More information about the Linuxppc64-dev mailing list