summaryrefslogtreecommitdiff
blob: ec93db138c7bddbe4e73e0ccbacfd028537b6f98 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
Index: linux-2.6.12/drivers/scsi/sata_sis.c
===================================================================
--- linux-2.6.12.orig/drivers/scsi/sata_sis.c
+++ linux-2.6.12/drivers/scsi/sata_sis.c
@@ -47,7 +47,10 @@ enum {
 	/* PCI configuration registers */
 	SIS_GENCTL		= 0x54, /* IDE General Control register */
 	SIS_SCR_BASE		= 0xc0, /* sata0 phy SCR registers */
-	SIS_SATA1_OFS		= 0x10, /* offset from sata0->sata1 phy regs */
+	SIS180_SATA1_OFS	= 0x10, /* offset from sata0->sata1 phy regs */
+	SIS182_SATA1_OFS	= 0x20, /* offset from sata0->sata1 phy regs */
+	SIS_PMR			= 0x90, /* port mapping register */
+	SIS_PMR_COMBINED	= 0x30, 
 
 	/* random bits */
 	SIS_FLAG_CFGSCR		= (1 << 30), /* host flag: SCRs via PCI cfg */
@@ -62,6 +65,7 @@ static void sis_scr_write (struct ata_po
 static struct pci_device_id sis_pci_tbl[] = {
 	{ PCI_VENDOR_ID_SI, 0x180, PCI_ANY_ID, PCI_ANY_ID, 0, 0, sis_180 },
 	{ PCI_VENDOR_ID_SI, 0x181, PCI_ANY_ID, PCI_ANY_ID, 0, 0, sis_180 },
+	{ PCI_VENDOR_ID_SI, 0x182, PCI_ANY_ID, PCI_ANY_ID, 0, 0, sis_180 },
 	{ }	/* terminate list */
 };
 
@@ -134,56 +138,94 @@ MODULE_LICENSE("GPL");
 MODULE_DEVICE_TABLE(pci, sis_pci_tbl);
 MODULE_VERSION(DRV_VERSION);
 
-static unsigned int get_scr_cfg_addr(unsigned int port_no, unsigned int sc_reg)
+static unsigned int get_scr_cfg_addr(unsigned int port_no, unsigned int sc_reg, int device)
 {
 	unsigned int addr = SIS_SCR_BASE + (4 * sc_reg);
 
-	if (port_no)
-		addr += SIS_SATA1_OFS;
+	if (port_no) 
+		if (device == 0x182)
+			addr += SIS182_SATA1_OFS;
+		else
+			addr += SIS180_SATA1_OFS;
 	return addr;
 }
 
 static u32 sis_scr_cfg_read (struct ata_port *ap, unsigned int sc_reg)
 {
 	struct pci_dev *pdev = to_pci_dev(ap->host_set->dev);
-	unsigned int cfg_addr = get_scr_cfg_addr(ap->port_no, sc_reg);
-	u32 val;
+	unsigned int cfg_addr = get_scr_cfg_addr(ap->port_no, sc_reg, pdev->device);
+	u32 val, val2;
+	u8 pmr;
 
 	if (sc_reg == SCR_ERROR) /* doesn't exist in PCI cfg space */
 		return 0xffffffff;
+
+	pci_read_config_byte(pdev, SIS_PMR, &pmr);
+	
 	pci_read_config_dword(pdev, cfg_addr, &val);
-	return val;
+
+	if ((pdev->device == 0x182) || (pmr & SIS_PMR_COMBINED)) 
+		pci_read_config_dword(pdev, cfg_addr+0x10, &val2);
+
+	return val|val2;
 }
 
 static void sis_scr_cfg_write (struct ata_port *ap, unsigned int scr, u32 val)
 {
 	struct pci_dev *pdev = to_pci_dev(ap->host_set->dev);
-	unsigned int cfg_addr = get_scr_cfg_addr(ap->port_no, scr);
+	unsigned int cfg_addr = get_scr_cfg_addr(ap->port_no, scr, pdev->device);
+	u8 pmr;
 
 	if (scr == SCR_ERROR) /* doesn't exist in PCI cfg space */
 		return;
+
+	pci_read_config_byte(pdev, SIS_PMR, &pmr);
+	
 	pci_write_config_dword(pdev, cfg_addr, val);
+
+	if ((pdev->device == 0x182) || (pmr & SIS_PMR_COMBINED))
+		pci_write_config_dword(pdev, cfg_addr+0x10, val);
 }
 
 static u32 sis_scr_read (struct ata_port *ap, unsigned int sc_reg)
 {
+	struct pci_dev *pdev = to_pci_dev(ap->host_set->dev);
+	u32 val,val2;
+	u8 pmr;
+
 	if (sc_reg > SCR_CONTROL)
 		return 0xffffffffU;
 
 	if (ap->flags & SIS_FLAG_CFGSCR)
 		return sis_scr_cfg_read(ap, sc_reg);
-	return inl(ap->ioaddr.scr_addr + (sc_reg * 4));
+
+	pci_read_config_byte(pdev, SIS_PMR, &pmr);
+
+	val = inl(ap->ioaddr.scr_addr + (sc_reg * 4));
+
+	if ((pdev->device == 0x182) || (pmr & SIS_PMR_COMBINED))
+		val2 = inl(ap->ioaddr.scr_addr + (sc_reg * 4)+0x10);
+
+	return val|val2;
 }
 
 static void sis_scr_write (struct ata_port *ap, unsigned int sc_reg, u32 val)
 {
+	struct pci_dev *pdev = to_pci_dev(ap->host_set->dev);
+	u8 pmr;
+
 	if (sc_reg > SCR_CONTROL)
 		return;
 
+	pci_read_config_byte(pdev, SIS_PMR, &pmr);
+	
 	if (ap->flags & SIS_FLAG_CFGSCR)
 		sis_scr_cfg_write(ap, sc_reg, val);
-	else
+	else {
 		outl(val, ap->ioaddr.scr_addr + (sc_reg * 4));
+		if ((pdev->device == 0x182) || (pmr & SIS_PMR_COMBINED))
+			outl(val, ap->ioaddr.scr_addr + (sc_reg * 4)+0x10);
+	}
 }
 
 /* move to PCI layer, integrate w/ MSI stuff */
@@ -205,6 +247,8 @@ static int sis_init_one (struct pci_dev 
 	u32 genctl;
 	struct ata_port_info *ppi;
 	int pci_dev_busy = 0;
+	u8 pmr;
+	u8 port2_start;
 
 	rc = pci_enable_device(pdev);
 	if (rc)
@@ -246,11 +290,27 @@ static int sis_init_one (struct pci_dev 
 		probe_ent->host_flags |= SIS_FLAG_CFGSCR;
 	}
 
+	pci_read_config_byte(pdev, SIS_PMR, &pmr);
+	if (ent->device != 0x182) {
+		if ((pmr & SIS_PMR_COMBINED) == 0) {
+			printk(KERN_INFO "sata_sis: Detected SiS 180/181 chipset in SATA mode\n");
+			port2_start=0x64;
+		}
+		else {
+			printk(KERN_INFO "sata_sis: Detected SiS 180/181 chipset in combined mode\n");
+			port2_start=0;
+		}
+	}
+	else {
+		printk(KERN_INFO "sata_sis: Detected SiS 182 chipset\n");
+		port2_start = 0x20;
+	}
+
 	if (!(probe_ent->host_flags & SIS_FLAG_CFGSCR)) {
 		probe_ent->port[0].scr_addr =
 			pci_resource_start(pdev, SIS_SCR_PCI_BAR);
 		probe_ent->port[1].scr_addr =
-			pci_resource_start(pdev, SIS_SCR_PCI_BAR) + 64;
+			pci_resource_start(pdev, SIS_SCR_PCI_BAR) + port2_start;
 	}
 
 	pci_set_master(pdev);