Skip to content
Projects
Groups
Snippets
Help
Loading...
Help
Support
Keyboard shortcuts
?
Submit feedback
Contribute to GitLab
Sign in / Register
Toggle navigation
L
linux
Project overview
Project overview
Details
Activity
Releases
Repository
Repository
Files
Commits
Branches
Tags
Contributors
Graph
Compare
Issues
0
Issues
0
List
Boards
Labels
Milestones
Merge Requests
0
Merge Requests
0
Analytics
Analytics
Repository
Value Stream
Wiki
Wiki
Snippets
Snippets
Members
Members
Collapse sidebar
Close sidebar
Activity
Graph
Create a new issue
Commits
Issue Boards
Open sidebar
nexedi
linux
Commits
2abc3c66
Commit
2abc3c66
authored
Apr 21, 2004
by
Jeff Garzik
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
[libata] Promise driver split part 1: clone to sx4
Clone sata_promise to sata_sx4.
parent
ef6a5260
Changes
3
Hide whitespace changes
Inline
Side-by-side
Showing
3 changed files
with
1877 additions
and
2 deletions
+1877
-2
drivers/scsi/Kconfig
drivers/scsi/Kconfig
+10
-2
drivers/scsi/Makefile
drivers/scsi/Makefile
+1
-0
drivers/scsi/sata_sx4.c
drivers/scsi/sata_sx4.c
+1866
-0
No files found.
drivers/scsi/Kconfig
View file @
2abc3c66
...
...
@@ -434,10 +434,18 @@ config SCSI_ATA_PIIX
If unsure, say N.
config SCSI_SATA_PROMISE
tristate "Promise SATA support"
tristate "Promise SATA
TX2/TX4
support"
depends on SCSI_SATA && PCI && EXPERIMENTAL
help
This option enables support for Promise Serial ATA.
This option enables support for Promise Serial ATA TX2/TX4.
If unsure, say N.
config SCSI_SATA_SX4
tristate "Promise SATA SX4 support"
depends on SCSI_SATA && PCI && EXPERIMENTAL
help
This option enables support for Promise Serial ATA SX4.
If unsure, say N.
...
...
drivers/scsi/Makefile
View file @
2abc3c66
...
...
@@ -124,6 +124,7 @@ obj-$(CONFIG_SCSI_SATA_SIL) += libata.o sata_sil.o
obj-$(CONFIG_SCSI_SATA_VIA)
+=
libata.o sata_via.o
obj-$(CONFIG_SCSI_SATA_VITESSE)
+=
libata.o sata_vsc.o
obj-$(CONFIG_SCSI_SATA_SIS)
+=
libata.o sata_sis.o
obj-$(CONFIG_SCSI_SATA_SX4)
+=
libata.o sata_sx4.o
obj-$(CONFIG_ARM)
+=
arm/
...
...
drivers/scsi/sata_sx4.c
0 → 100644
View file @
2abc3c66
/*
* sata_promise.c - Promise SATA
*
* Copyright 2003-2004 Red Hat, Inc.
*
* The contents of this file are subject to the Open
* Software License version 1.1 that can be found at
* http://www.opensource.org/licenses/osl-1.1.txt and is included herein
* by reference.
*
* Alternatively, the contents of this file may be used under the terms
* of the GNU General Public License version 2 (the "GPL") as distributed
* in the kernel source COPYING file, in which case the provisions of
* the GPL are applicable instead of the above. If you wish to allow
* the use of your version of this file only under the terms of the
* GPL and not to allow others to use your version of this file under
* the OSL, indicate your decision by deleting the provisions above and
* replace them with the notice and other provisions required by the GPL.
* If you do not delete the provisions above, a recipient may use your
* version of this file under either the OSL or the GPL.
*
*/
#include <linux/kernel.h>
#include <linux/module.h>
#include <linux/pci.h>
#include <linux/init.h>
#include <linux/blkdev.h>
#include <linux/delay.h>
#include <linux/interrupt.h>
#include <linux/sched.h>
#include "scsi.h"
#include "hosts.h"
#include <linux/libata.h>
#include <asm/io.h>
#define DRV_NAME "sata_promise"
#define DRV_VERSION "0.92"
enum
{
PDC_PRD_TBL
=
0x44
,
/* Direct command DMA table addr */
PDC_PKT_SUBMIT
=
0x40
,
/* Command packet pointer addr */
PDC_HDMA_PKT_SUBMIT
=
0x100
,
/* Host DMA packet pointer addr */
PDC_INT_SEQMASK
=
0x40
,
/* Mask of asserted SEQ INTs */
PDC_TBG_MODE
=
0x41
,
/* TBG mode */
PDC_FLASH_CTL
=
0x44
,
/* Flash control register */
PDC_PCI_CTL
=
0x48
,
/* PCI control and status register */
PDC_GLOBAL_CTL
=
0x48
,
/* Global control/status (per port) */
PDC_CTLSTAT
=
0x60
,
/* IDE control and status (per port) */
PDC_SATA_PLUG_CSR
=
0x6C
,
/* SATA Plug control/status reg */
PDC_SLEW_CTL
=
0x470
,
/* slew rate control reg */
PDC_HDMA_CTLSTAT
=
0x12C
,
/* Host DMA control / status */
PDC_20621_SEQCTL
=
0x400
,
PDC_20621_SEQMASK
=
0x480
,
PDC_20621_GENERAL_CTL
=
0x484
,
PDC_20621_PAGE_SIZE
=
(
32
*
1024
),
/* chosen, not constant, values; we design our own DIMM mem map */
PDC_20621_DIMM_WINDOW
=
0x0C
,
/* page# for 32K DIMM window */
PDC_20621_DIMM_BASE
=
0x00200000
,
PDC_20621_DIMM_DATA
=
(
64
*
1024
),
PDC_DIMM_DATA_STEP
=
(
256
*
1024
),
PDC_DIMM_WINDOW_STEP
=
(
8
*
1024
),
PDC_DIMM_HOST_PRD
=
(
6
*
1024
),
PDC_DIMM_HOST_PKT
=
(
128
*
0
),
PDC_DIMM_HPKT_PRD
=
(
128
*
1
),
PDC_DIMM_ATA_PKT
=
(
128
*
2
),
PDC_DIMM_APKT_PRD
=
(
128
*
3
),
PDC_DIMM_HEADER_SZ
=
PDC_DIMM_APKT_PRD
+
128
,
PDC_PAGE_WINDOW
=
0x40
,
PDC_PAGE_DATA
=
PDC_PAGE_WINDOW
+
(
PDC_20621_DIMM_DATA
/
PDC_20621_PAGE_SIZE
),
PDC_PAGE_SET
=
PDC_DIMM_DATA_STEP
/
PDC_20621_PAGE_SIZE
,
PDC_CHIP0_OFS
=
0xC0000
,
/* offset of chip #0 */
PDC_20621_ERR_MASK
=
(
1
<<
19
)
|
(
1
<<
20
)
|
(
1
<<
21
)
|
(
1
<<
22
)
|
(
1
<<
23
),
PDC_ERR_MASK
=
(
1
<<
19
)
|
(
1
<<
20
)
|
(
1
<<
21
)
|
(
1
<<
22
)
|
(
1
<<
8
)
|
(
1
<<
9
)
|
(
1
<<
10
),
board_2037x
=
0
,
/* FastTrak S150 TX2plus */
board_20319
=
1
,
/* FastTrak S150 TX4 */
board_20621
=
2
,
/* FastTrak S150 SX4 */
PDC_HAS_PATA
=
(
1
<<
1
),
/* PDC20375 has PATA */
PDC_FLAG_20621
=
(
1
<<
30
),
/* we have a 20621 */
PDC_RESET
=
(
1
<<
11
),
/* HDMA reset */
PDC_MAX_HDMA
=
32
,
PDC_HDMA_Q_MASK
=
(
PDC_MAX_HDMA
-
1
),
PDC_DIMM0_SPD_DEV_ADDRESS
=
0x50
,
PDC_DIMM1_SPD_DEV_ADDRESS
=
0x51
,
PDC_MAX_DIMM_MODULE
=
0x02
,
PDC_I2C_CONTROL_OFFSET
=
0x48
,
PDC_I2C_ADDR_DATA_OFFSET
=
0x4C
,
PDC_DIMM0_CONTROL_OFFSET
=
0x80
,
PDC_DIMM1_CONTROL_OFFSET
=
0x84
,
PDC_SDRAM_CONTROL_OFFSET
=
0x88
,
PDC_I2C_WRITE
=
0x00000000
,
PDC_I2C_READ
=
0x00000040
,
PDC_I2C_START
=
0x00000080
,
PDC_I2C_MASK_INT
=
0x00000020
,
PDC_I2C_COMPLETE
=
0x00010000
,
PDC_I2C_NO_ACK
=
0x00100000
,
PDC_DIMM_SPD_SUBADDRESS_START
=
0x00
,
PDC_DIMM_SPD_SUBADDRESS_END
=
0x7F
,
PDC_DIMM_SPD_ROW_NUM
=
3
,
PDC_DIMM_SPD_COLUMN_NUM
=
4
,
PDC_DIMM_SPD_MODULE_ROW
=
5
,
PDC_DIMM_SPD_TYPE
=
11
,
PDC_DIMM_SPD_FRESH_RATE
=
12
,
PDC_DIMM_SPD_BANK_NUM
=
17
,
PDC_DIMM_SPD_CAS_LATENCY
=
18
,
PDC_DIMM_SPD_ATTRIBUTE
=
21
,
PDC_DIMM_SPD_ROW_PRE_CHARGE
=
27
,
PDC_DIMM_SPD_ROW_ACTIVE_DELAY
=
28
,
PDC_DIMM_SPD_RAS_CAS_DELAY
=
29
,
PDC_DIMM_SPD_ACTIVE_PRECHARGE
=
30
,
PDC_DIMM_SPD_SYSTEM_FREQ
=
126
,
PDC_CTL_STATUS
=
0x08
,
PDC_DIMM_WINDOW_CTLR
=
0x0C
,
PDC_TIME_CONTROL
=
0x3C
,
PDC_TIME_PERIOD
=
0x40
,
PDC_TIME_COUNTER
=
0x44
,
PDC_GENERAL_CTLR
=
0x484
,
PCI_PLL_INIT
=
0x8A531824
,
PCI_X_TCOUNT
=
0xEE1E5CFF
};
struct
pdc_port_priv
{
u8
dimm_buf
[(
ATA_PRD_SZ
*
ATA_MAX_PRD
)
+
512
];
u8
*
pkt
;
dma_addr_t
pkt_dma
;
};
struct
pdc_host_priv
{
void
*
dimm_mmio
;
unsigned
int
doing_hdma
;
unsigned
int
hdma_prod
;
unsigned
int
hdma_cons
;
struct
{
struct
ata_queued_cmd
*
qc
;
unsigned
int
seq
;
unsigned
long
pkt_ofs
;
}
hdma
[
32
];
};
static
u32
pdc_sata_scr_read
(
struct
ata_port
*
ap
,
unsigned
int
sc_reg
);
static
void
pdc_sata_scr_write
(
struct
ata_port
*
ap
,
unsigned
int
sc_reg
,
u32
val
);
static
int
pdc_sata_init_one
(
struct
pci_dev
*
pdev
,
const
struct
pci_device_id
*
ent
);
static
void
pdc_dma_start
(
struct
ata_queued_cmd
*
qc
);
static
void
pdc20621_dma_start
(
struct
ata_queued_cmd
*
qc
);
static
irqreturn_t
pdc_interrupt
(
int
irq
,
void
*
dev_instance
,
struct
pt_regs
*
regs
);
static
irqreturn_t
pdc20621_interrupt
(
int
irq
,
void
*
dev_instance
,
struct
pt_regs
*
regs
);
static
void
pdc_eng_timeout
(
struct
ata_port
*
ap
);
static
void
pdc_20621_phy_reset
(
struct
ata_port
*
ap
);
static
int
pdc_port_start
(
struct
ata_port
*
ap
);
static
void
pdc_port_stop
(
struct
ata_port
*
ap
);
static
void
pdc_phy_reset
(
struct
ata_port
*
ap
);
static
void
pdc_fill_sg
(
struct
ata_queued_cmd
*
qc
);
static
void
pdc20621_fill_sg
(
struct
ata_queued_cmd
*
qc
);
static
void
pdc_tf_load_mmio
(
struct
ata_port
*
ap
,
struct
ata_taskfile
*
tf
);
static
void
pdc_exec_command_mmio
(
struct
ata_port
*
ap
,
struct
ata_taskfile
*
tf
);
static
void
pdc20621_host_stop
(
struct
ata_host_set
*
host_set
);
static
inline
void
pdc_dma_complete
(
struct
ata_port
*
ap
,
struct
ata_queued_cmd
*
qc
,
int
have_err
);
static
unsigned
int
pdc20621_dimm_init
(
struct
ata_probe_ent
*
pe
);
static
int
pdc20621_detect_dimm
(
struct
ata_probe_ent
*
pe
);
static
unsigned
int
pdc20621_i2c_read
(
struct
ata_probe_ent
*
pe
,
u32
device
,
u32
subaddr
,
u32
*
pdata
);
static
int
pdc20621_prog_dimm0
(
struct
ata_probe_ent
*
pe
);
static
unsigned
int
pdc20621_prog_dimm_global
(
struct
ata_probe_ent
*
pe
);
#ifdef ATA_VERBOSE_DEBUG
static
void
pdc20621_get_from_dimm
(
struct
ata_probe_ent
*
pe
,
void
*
psource
,
u32
offset
,
u32
size
);
#endif
static
void
pdc20621_put_to_dimm
(
struct
ata_probe_ent
*
pe
,
void
*
psource
,
u32
offset
,
u32
size
);
static
Scsi_Host_Template
pdc_sata_sht
=
{
.
module
=
THIS_MODULE
,
.
name
=
DRV_NAME
,
.
queuecommand
=
ata_scsi_queuecmd
,
.
eh_strategy_handler
=
ata_scsi_error
,
.
can_queue
=
ATA_DEF_QUEUE
,
.
this_id
=
ATA_SHT_THIS_ID
,
.
sg_tablesize
=
LIBATA_MAX_PRD
,
.
max_sectors
=
ATA_MAX_SECTORS
,
.
cmd_per_lun
=
ATA_SHT_CMD_PER_LUN
,
.
emulated
=
ATA_SHT_EMULATED
,
.
use_clustering
=
ATA_SHT_USE_CLUSTERING
,
.
proc_name
=
DRV_NAME
,
.
dma_boundary
=
ATA_DMA_BOUNDARY
,
.
slave_configure
=
ata_scsi_slave_config
,
.
bios_param
=
ata_std_bios_param
,
};
static
struct
ata_port_operations
pdc_sata_ops
=
{
.
port_disable
=
ata_port_disable
,
.
tf_load
=
pdc_tf_load_mmio
,
.
tf_read
=
ata_tf_read_mmio
,
.
check_status
=
ata_check_status_mmio
,
.
exec_command
=
pdc_exec_command_mmio
,
.
phy_reset
=
pdc_phy_reset
,
.
bmdma_start
=
pdc_dma_start
,
.
fill_sg
=
pdc_fill_sg
,
.
eng_timeout
=
pdc_eng_timeout
,
.
irq_handler
=
pdc_interrupt
,
.
scr_read
=
pdc_sata_scr_read
,
.
scr_write
=
pdc_sata_scr_write
,
.
port_start
=
pdc_port_start
,
.
port_stop
=
pdc_port_stop
,
};
static
struct
ata_port_operations
pdc_20621_ops
=
{
.
port_disable
=
ata_port_disable
,
.
tf_load
=
pdc_tf_load_mmio
,
.
tf_read
=
ata_tf_read_mmio
,
.
check_status
=
ata_check_status_mmio
,
.
exec_command
=
pdc_exec_command_mmio
,
.
phy_reset
=
pdc_20621_phy_reset
,
.
bmdma_start
=
pdc20621_dma_start
,
.
fill_sg
=
pdc20621_fill_sg
,
.
eng_timeout
=
pdc_eng_timeout
,
.
irq_handler
=
pdc20621_interrupt
,
.
port_start
=
pdc_port_start
,
.
port_stop
=
pdc_port_stop
,
.
host_stop
=
pdc20621_host_stop
,
};
static
struct
ata_port_info
pdc_port_info
[]
=
{
/* board_2037x */
{
.
sht
=
&
pdc_sata_sht
,
.
host_flags
=
ATA_FLAG_SATA
|
ATA_FLAG_NO_LEGACY
|
ATA_FLAG_SRST
|
ATA_FLAG_MMIO
,
.
pio_mask
=
0x03
,
/* pio3-4 */
.
udma_mask
=
0x7f
,
/* udma0-6 ; FIXME */
.
port_ops
=
&
pdc_sata_ops
,
},
/* board_20319 */
{
.
sht
=
&
pdc_sata_sht
,
.
host_flags
=
ATA_FLAG_SATA
|
ATA_FLAG_NO_LEGACY
|
ATA_FLAG_SRST
|
ATA_FLAG_MMIO
,
.
pio_mask
=
0x03
,
/* pio3-4 */
.
udma_mask
=
0x7f
,
/* udma0-6 ; FIXME */
.
port_ops
=
&
pdc_sata_ops
,
},
/* board_20621 */
{
.
sht
=
&
pdc_sata_sht
,
.
host_flags
=
ATA_FLAG_SATA
|
ATA_FLAG_NO_LEGACY
|
ATA_FLAG_SRST
|
ATA_FLAG_MMIO
|
PDC_FLAG_20621
,
.
pio_mask
=
0x03
,
/* pio3-4 */
.
udma_mask
=
0x7f
,
/* udma0-6 ; FIXME */
.
port_ops
=
&
pdc_20621_ops
,
},
};
static
struct
pci_device_id
pdc_sata_pci_tbl
[]
=
{
{
PCI_VENDOR_ID_PROMISE
,
0x3371
,
PCI_ANY_ID
,
PCI_ANY_ID
,
0
,
0
,
board_2037x
},
{
PCI_VENDOR_ID_PROMISE
,
0x3373
,
PCI_ANY_ID
,
PCI_ANY_ID
,
0
,
0
,
board_2037x
},
{
PCI_VENDOR_ID_PROMISE
,
0x3375
,
PCI_ANY_ID
,
PCI_ANY_ID
,
0
,
0
,
board_2037x
},
{
PCI_VENDOR_ID_PROMISE
,
0x3376
,
PCI_ANY_ID
,
PCI_ANY_ID
,
0
,
0
,
board_2037x
},
{
PCI_VENDOR_ID_PROMISE
,
0x3318
,
PCI_ANY_ID
,
PCI_ANY_ID
,
0
,
0
,
board_20319
},
{
PCI_VENDOR_ID_PROMISE
,
0x3319
,
PCI_ANY_ID
,
PCI_ANY_ID
,
0
,
0
,
board_20319
},
{
PCI_VENDOR_ID_PROMISE
,
0x6622
,
PCI_ANY_ID
,
PCI_ANY_ID
,
0
,
0
,
board_20621
},
{
}
/* terminate list */
};
static
struct
pci_driver
pdc_sata_pci_driver
=
{
.
name
=
DRV_NAME
,
.
id_table
=
pdc_sata_pci_tbl
,
.
probe
=
pdc_sata_init_one
,
.
remove
=
ata_pci_remove_one
,
};
static
void
pdc20621_host_stop
(
struct
ata_host_set
*
host_set
)
{
struct
pdc_host_priv
*
hpriv
=
host_set
->
private_data
;
void
*
dimm_mmio
=
hpriv
->
dimm_mmio
;
iounmap
(
dimm_mmio
);
kfree
(
hpriv
);
}
static
int
pdc_port_start
(
struct
ata_port
*
ap
)
{
struct
pci_dev
*
pdev
=
ap
->
host_set
->
pdev
;
struct
pdc_port_priv
*
pp
;
int
rc
;
rc
=
ata_port_start
(
ap
);
if
(
rc
)
return
rc
;
pp
=
kmalloc
(
sizeof
(
*
pp
),
GFP_KERNEL
);
if
(
!
pp
)
{
rc
=
-
ENOMEM
;
goto
err_out
;
}
memset
(
pp
,
0
,
sizeof
(
*
pp
));
pp
->
pkt
=
pci_alloc_consistent
(
pdev
,
128
,
&
pp
->
pkt_dma
);
if
(
!
pp
->
pkt
)
{
rc
=
-
ENOMEM
;
goto
err_out_kfree
;
}
ap
->
private_data
=
pp
;
return
0
;
err_out_kfree:
kfree
(
pp
);
err_out:
ata_port_stop
(
ap
);
return
rc
;
}
static
void
pdc_port_stop
(
struct
ata_port
*
ap
)
{
struct
pci_dev
*
pdev
=
ap
->
host_set
->
pdev
;
struct
pdc_port_priv
*
pp
=
ap
->
private_data
;
ap
->
private_data
=
NULL
;
pci_free_consistent
(
pdev
,
128
,
pp
->
pkt
,
pp
->
pkt_dma
);
kfree
(
pp
);
ata_port_stop
(
ap
);
}
static
void
pdc_20621_phy_reset
(
struct
ata_port
*
ap
)
{
VPRINTK
(
"ENTER
\n
"
);
ap
->
cbl
=
ATA_CBL_SATA
;
ata_port_probe
(
ap
);
ata_bus_reset
(
ap
);
}
static
void
pdc_reset_port
(
struct
ata_port
*
ap
)
{
void
*
mmio
=
(
void
*
)
ap
->
ioaddr
.
cmd_addr
+
PDC_CTLSTAT
;
unsigned
int
i
;
u32
tmp
;
for
(
i
=
11
;
i
>
0
;
i
--
)
{
tmp
=
readl
(
mmio
);
if
(
tmp
&
PDC_RESET
)
break
;
udelay
(
100
);
tmp
|=
PDC_RESET
;
writel
(
tmp
,
mmio
);
}
tmp
&=
~
PDC_RESET
;
writel
(
tmp
,
mmio
);
readl
(
mmio
);
/* flush */
}
static
void
pdc_phy_reset
(
struct
ata_port
*
ap
)
{
pdc_reset_port
(
ap
);
sata_phy_reset
(
ap
);
}
static
u32
pdc_sata_scr_read
(
struct
ata_port
*
ap
,
unsigned
int
sc_reg
)
{
if
(
sc_reg
>
SCR_CONTROL
)
return
0xffffffffU
;
return
readl
((
void
*
)
ap
->
ioaddr
.
scr_addr
+
(
sc_reg
*
4
));
}
static
void
pdc_sata_scr_write
(
struct
ata_port
*
ap
,
unsigned
int
sc_reg
,
u32
val
)
{
if
(
sc_reg
>
SCR_CONTROL
)
return
;
writel
(
val
,
(
void
*
)
ap
->
ioaddr
.
scr_addr
+
(
sc_reg
*
4
));
}
enum
pdc_packet_bits
{
PDC_PKT_READ
=
(
1
<<
2
),
PDC_PKT_NODATA
=
(
1
<<
3
),
PDC_PKT_SIZEMASK
=
(
1
<<
7
)
|
(
1
<<
6
)
|
(
1
<<
5
),
PDC_PKT_CLEAR_BSY
=
(
1
<<
4
),
PDC_PKT_WAIT_DRDY
=
(
1
<<
3
)
|
(
1
<<
4
),
PDC_LAST_REG
=
(
1
<<
3
),
PDC_REG_DEVCTL
=
(
1
<<
3
)
|
(
1
<<
2
)
|
(
1
<<
1
),
};
static
inline
unsigned
int
pdc_pkt_header
(
struct
ata_taskfile
*
tf
,
dma_addr_t
sg_table
,
unsigned
int
devno
,
u8
*
buf
)
{
u8
dev_reg
;
u32
*
buf32
=
(
u32
*
)
buf
;
/* set control bits (byte 0), zero delay seq id (byte 3),
* and seq id (byte 2)
*/
switch
(
tf
->
protocol
)
{
case
ATA_PROT_DMA
:
if
(
!
(
tf
->
flags
&
ATA_TFLAG_WRITE
))
buf32
[
0
]
=
cpu_to_le32
(
PDC_PKT_READ
);
else
buf32
[
0
]
=
0
;
break
;
case
ATA_PROT_NODATA
:
buf32
[
0
]
=
cpu_to_le32
(
PDC_PKT_NODATA
);
break
;
default:
BUG
();
break
;
}
buf32
[
1
]
=
cpu_to_le32
(
sg_table
);
/* S/G table addr */
buf32
[
2
]
=
0
;
/* no next-packet */
if
(
devno
==
0
)
dev_reg
=
ATA_DEVICE_OBS
;
else
dev_reg
=
ATA_DEVICE_OBS
|
ATA_DEV1
;
/* select device */
buf
[
12
]
=
(
1
<<
5
)
|
PDC_PKT_CLEAR_BSY
|
ATA_REG_DEVICE
;
buf
[
13
]
=
dev_reg
;
/* device control register */
buf
[
14
]
=
(
1
<<
5
)
|
PDC_REG_DEVCTL
;
buf
[
15
]
=
tf
->
ctl
;
return
16
;
/* offset of next byte */
}
static
inline
unsigned
int
pdc_pkt_footer
(
struct
ata_taskfile
*
tf
,
u8
*
buf
,
unsigned
int
i
)
{
if
(
tf
->
flags
&
ATA_TFLAG_DEVICE
)
{
buf
[
i
++
]
=
(
1
<<
5
)
|
ATA_REG_DEVICE
;
buf
[
i
++
]
=
tf
->
device
;
}
/* and finally the command itself; also includes end-of-pkt marker */
buf
[
i
++
]
=
(
1
<<
5
)
|
PDC_LAST_REG
|
ATA_REG_CMD
;
buf
[
i
++
]
=
tf
->
command
;
return
i
;
}
static
inline
unsigned
int
pdc_prep_lba28
(
struct
ata_taskfile
*
tf
,
u8
*
buf
,
unsigned
int
i
)
{
/* the "(1 << 5)" should be read "(count << 5)" */
/* ATA command block registers */
buf
[
i
++
]
=
(
1
<<
5
)
|
ATA_REG_FEATURE
;
buf
[
i
++
]
=
tf
->
feature
;
buf
[
i
++
]
=
(
1
<<
5
)
|
ATA_REG_NSECT
;
buf
[
i
++
]
=
tf
->
nsect
;
buf
[
i
++
]
=
(
1
<<
5
)
|
ATA_REG_LBAL
;
buf
[
i
++
]
=
tf
->
lbal
;
buf
[
i
++
]
=
(
1
<<
5
)
|
ATA_REG_LBAM
;
buf
[
i
++
]
=
tf
->
lbam
;
buf
[
i
++
]
=
(
1
<<
5
)
|
ATA_REG_LBAH
;
buf
[
i
++
]
=
tf
->
lbah
;
return
i
;
}
static
inline
unsigned
int
pdc_prep_lba48
(
struct
ata_taskfile
*
tf
,
u8
*
buf
,
unsigned
int
i
)
{
/* the "(2 << 5)" should be read "(count << 5)" */
/* ATA command block registers */
buf
[
i
++
]
=
(
2
<<
5
)
|
ATA_REG_FEATURE
;
buf
[
i
++
]
=
tf
->
hob_feature
;
buf
[
i
++
]
=
tf
->
feature
;
buf
[
i
++
]
=
(
2
<<
5
)
|
ATA_REG_NSECT
;
buf
[
i
++
]
=
tf
->
hob_nsect
;
buf
[
i
++
]
=
tf
->
nsect
;
buf
[
i
++
]
=
(
2
<<
5
)
|
ATA_REG_LBAL
;
buf
[
i
++
]
=
tf
->
hob_lbal
;
buf
[
i
++
]
=
tf
->
lbal
;
buf
[
i
++
]
=
(
2
<<
5
)
|
ATA_REG_LBAM
;
buf
[
i
++
]
=
tf
->
hob_lbam
;
buf
[
i
++
]
=
tf
->
lbam
;
buf
[
i
++
]
=
(
2
<<
5
)
|
ATA_REG_LBAH
;
buf
[
i
++
]
=
tf
->
hob_lbah
;
buf
[
i
++
]
=
tf
->
lbah
;
return
i
;
}
static
inline
void
pdc20621_ata_sg
(
struct
ata_taskfile
*
tf
,
u8
*
buf
,
unsigned
int
portno
,
unsigned
int
total_len
)
{
u32
addr
;
unsigned
int
dw
=
PDC_DIMM_APKT_PRD
>>
2
;
u32
*
buf32
=
(
u32
*
)
buf
;
/* output ATA packet S/G table */
addr
=
PDC_20621_DIMM_BASE
+
PDC_20621_DIMM_DATA
+
(
PDC_DIMM_DATA_STEP
*
portno
);
VPRINTK
(
"ATA sg addr 0x%x, %d
\n
"
,
addr
,
addr
);
buf32
[
dw
]
=
cpu_to_le32
(
addr
);
buf32
[
dw
+
1
]
=
cpu_to_le32
(
total_len
|
ATA_PRD_EOT
);
VPRINTK
(
"ATA PSG @ %x == (0x%x, 0x%x)
\n
"
,
PDC_20621_DIMM_BASE
+
(
PDC_DIMM_WINDOW_STEP
*
portno
)
+
PDC_DIMM_APKT_PRD
,
buf32
[
dw
],
buf32
[
dw
+
1
]);
}
static
inline
void
pdc20621_host_sg
(
struct
ata_taskfile
*
tf
,
u8
*
buf
,
unsigned
int
portno
,
unsigned
int
total_len
)
{
u32
addr
;
unsigned
int
dw
=
PDC_DIMM_HPKT_PRD
>>
2
;
u32
*
buf32
=
(
u32
*
)
buf
;
/* output Host DMA packet S/G table */
addr
=
PDC_20621_DIMM_BASE
+
PDC_20621_DIMM_DATA
+
(
PDC_DIMM_DATA_STEP
*
portno
);
buf32
[
dw
]
=
cpu_to_le32
(
addr
);
buf32
[
dw
+
1
]
=
cpu_to_le32
(
total_len
|
ATA_PRD_EOT
);
VPRINTK
(
"HOST PSG @ %x == (0x%x, 0x%x)
\n
"
,
PDC_20621_DIMM_BASE
+
(
PDC_DIMM_WINDOW_STEP
*
portno
)
+
PDC_DIMM_HPKT_PRD
,
buf32
[
dw
],
buf32
[
dw
+
1
]);
}
static
inline
unsigned
int
pdc20621_ata_pkt
(
struct
ata_taskfile
*
tf
,
unsigned
int
devno
,
u8
*
buf
,
unsigned
int
portno
)
{
unsigned
int
i
,
dw
;
u32
*
buf32
=
(
u32
*
)
buf
;
u8
dev_reg
;
unsigned
int
dimm_sg
=
PDC_20621_DIMM_BASE
+
(
PDC_DIMM_WINDOW_STEP
*
portno
)
+
PDC_DIMM_APKT_PRD
;
VPRINTK
(
"ENTER, dimm_sg == 0x%x, %d
\n
"
,
dimm_sg
,
dimm_sg
);
i
=
PDC_DIMM_ATA_PKT
;
/*
* Set up ATA packet
*/
if
((
tf
->
protocol
==
ATA_PROT_DMA
)
&&
(
!
(
tf
->
flags
&
ATA_TFLAG_WRITE
)))
buf
[
i
++
]
=
PDC_PKT_READ
;
else
if
(
tf
->
protocol
==
ATA_PROT_NODATA
)
buf
[
i
++
]
=
PDC_PKT_NODATA
;
else
buf
[
i
++
]
=
0
;
buf
[
i
++
]
=
0
;
/* reserved */
buf
[
i
++
]
=
portno
+
1
;
/* seq. id */
buf
[
i
++
]
=
0xff
;
/* delay seq. id */
/* dimm dma S/G, and next-pkt */
dw
=
i
>>
2
;
buf32
[
dw
]
=
cpu_to_le32
(
dimm_sg
);
buf32
[
dw
+
1
]
=
0
;
i
+=
8
;
if
(
devno
==
0
)
dev_reg
=
ATA_DEVICE_OBS
;
else
dev_reg
=
ATA_DEVICE_OBS
|
ATA_DEV1
;
/* select device */
buf
[
i
++
]
=
(
1
<<
5
)
|
PDC_PKT_CLEAR_BSY
|
ATA_REG_DEVICE
;
buf
[
i
++
]
=
dev_reg
;
/* device control register */
buf
[
i
++
]
=
(
1
<<
5
)
|
PDC_REG_DEVCTL
;
buf
[
i
++
]
=
tf
->
ctl
;
return
i
;
}
static
inline
void
pdc20621_host_pkt
(
struct
ata_taskfile
*
tf
,
u8
*
buf
,
unsigned
int
portno
)
{
unsigned
int
dw
;
u32
tmp
,
*
buf32
=
(
u32
*
)
buf
;
unsigned
int
host_sg
=
PDC_20621_DIMM_BASE
+
(
PDC_DIMM_WINDOW_STEP
*
portno
)
+
PDC_DIMM_HOST_PRD
;
unsigned
int
dimm_sg
=
PDC_20621_DIMM_BASE
+
(
PDC_DIMM_WINDOW_STEP
*
portno
)
+
PDC_DIMM_HPKT_PRD
;
VPRINTK
(
"ENTER, dimm_sg == 0x%x, %d
\n
"
,
dimm_sg
,
dimm_sg
);
VPRINTK
(
"host_sg == 0x%x, %d
\n
"
,
host_sg
,
host_sg
);
dw
=
PDC_DIMM_HOST_PKT
>>
2
;
/*
* Set up Host DMA packet
*/
if
((
tf
->
protocol
==
ATA_PROT_DMA
)
&&
(
!
(
tf
->
flags
&
ATA_TFLAG_WRITE
)))
tmp
=
PDC_PKT_READ
;
else
tmp
=
0
;
tmp
|=
((
portno
+
1
+
4
)
<<
16
);
/* seq. id */
tmp
|=
(
0xff
<<
24
);
/* delay seq. id */
buf32
[
dw
+
0
]
=
cpu_to_le32
(
tmp
);
buf32
[
dw
+
1
]
=
cpu_to_le32
(
host_sg
);
buf32
[
dw
+
2
]
=
cpu_to_le32
(
dimm_sg
);
buf32
[
dw
+
3
]
=
0
;
VPRINTK
(
"HOST PKT @ %x == (0x%x 0x%x 0x%x 0x%x)
\n
"
,
PDC_20621_DIMM_BASE
+
(
PDC_DIMM_WINDOW_STEP
*
portno
)
+
PDC_DIMM_HOST_PKT
,
buf32
[
dw
+
0
],
buf32
[
dw
+
1
],
buf32
[
dw
+
2
],
buf32
[
dw
+
3
]);
}
static
void
pdc20621_fill_sg
(
struct
ata_queued_cmd
*
qc
)
{
struct
scatterlist
*
sg
=
qc
->
sg
;
struct
ata_port
*
ap
=
qc
->
ap
;
struct
pdc_port_priv
*
pp
=
ap
->
private_data
;
void
*
mmio
=
ap
->
host_set
->
mmio_base
;
struct
pdc_host_priv
*
hpriv
=
ap
->
host_set
->
private_data
;
void
*
dimm_mmio
=
hpriv
->
dimm_mmio
;
unsigned
int
portno
=
ap
->
port_no
;
unsigned
int
i
,
last
,
idx
,
total_len
=
0
,
sgt_len
;
u32
*
buf
=
(
u32
*
)
&
pp
->
dimm_buf
[
PDC_DIMM_HEADER_SZ
];
VPRINTK
(
"ata%u: ENTER
\n
"
,
ap
->
id
);
/* hard-code chip #0 */
mmio
+=
PDC_CHIP0_OFS
;
/*
* Build S/G table
*/
last
=
qc
->
n_elem
;
idx
=
0
;
for
(
i
=
0
;
i
<
last
;
i
++
)
{
buf
[
idx
++
]
=
cpu_to_le32
(
sg_dma_address
(
&
sg
[
i
]));
buf
[
idx
++
]
=
cpu_to_le32
(
sg_dma_len
(
&
sg
[
i
]));
total_len
+=
sg
[
i
].
length
;
}
buf
[
idx
-
1
]
|=
cpu_to_le32
(
ATA_PRD_EOT
);
sgt_len
=
idx
*
4
;
/*
* Build ATA, host DMA packets
*/
pdc20621_host_sg
(
&
qc
->
tf
,
&
pp
->
dimm_buf
[
0
],
portno
,
total_len
);
pdc20621_host_pkt
(
&
qc
->
tf
,
&
pp
->
dimm_buf
[
0
],
portno
);
pdc20621_ata_sg
(
&
qc
->
tf
,
&
pp
->
dimm_buf
[
0
],
portno
,
total_len
);
i
=
pdc20621_ata_pkt
(
&
qc
->
tf
,
qc
->
dev
->
devno
,
&
pp
->
dimm_buf
[
0
],
portno
);
if
(
qc
->
tf
.
flags
&
ATA_TFLAG_LBA48
)
i
=
pdc_prep_lba48
(
&
qc
->
tf
,
&
pp
->
dimm_buf
[
0
],
i
);
else
i
=
pdc_prep_lba28
(
&
qc
->
tf
,
&
pp
->
dimm_buf
[
0
],
i
);
pdc_pkt_footer
(
&
qc
->
tf
,
&
pp
->
dimm_buf
[
0
],
i
);
/* copy three S/G tables and two packets to DIMM MMIO window */
memcpy_toio
(
dimm_mmio
+
(
portno
*
PDC_DIMM_WINDOW_STEP
),
&
pp
->
dimm_buf
,
PDC_DIMM_HEADER_SZ
);
memcpy_toio
(
dimm_mmio
+
(
portno
*
PDC_DIMM_WINDOW_STEP
)
+
PDC_DIMM_HOST_PRD
,
&
pp
->
dimm_buf
[
PDC_DIMM_HEADER_SZ
],
sgt_len
);
/* force host FIFO dump */
writel
(
0x00000001
,
mmio
+
PDC_20621_GENERAL_CTL
);
readl
(
dimm_mmio
);
/* MMIO PCI posting flush */
VPRINTK
(
"ata pkt buf ofs %u, prd size %u, mmio copied
\n
"
,
i
,
sgt_len
);
}
static
void
__pdc20621_push_hdma
(
struct
ata_queued_cmd
*
qc
,
unsigned
int
seq
,
u32
pkt_ofs
)
{
struct
ata_port
*
ap
=
qc
->
ap
;
struct
ata_host_set
*
host_set
=
ap
->
host_set
;
void
*
mmio
=
host_set
->
mmio_base
;
/* hard-code chip #0 */
mmio
+=
PDC_CHIP0_OFS
;
writel
(
0x00000001
,
mmio
+
PDC_20621_SEQCTL
+
(
seq
*
4
));
readl
(
mmio
+
PDC_20621_SEQCTL
+
(
seq
*
4
));
/* flush */
writel
(
pkt_ofs
,
mmio
+
PDC_HDMA_PKT_SUBMIT
);
readl
(
mmio
+
PDC_HDMA_PKT_SUBMIT
);
/* flush */
}
static
void
pdc20621_push_hdma
(
struct
ata_queued_cmd
*
qc
,
unsigned
int
seq
,
u32
pkt_ofs
)
{
struct
ata_port
*
ap
=
qc
->
ap
;
struct
pdc_host_priv
*
pp
=
ap
->
host_set
->
private_data
;
unsigned
int
idx
=
pp
->
hdma_prod
&
PDC_HDMA_Q_MASK
;
if
(
!
pp
->
doing_hdma
)
{
__pdc20621_push_hdma
(
qc
,
seq
,
pkt_ofs
);
pp
->
doing_hdma
=
1
;
return
;
}
pp
->
hdma
[
idx
].
qc
=
qc
;
pp
->
hdma
[
idx
].
seq
=
seq
;
pp
->
hdma
[
idx
].
pkt_ofs
=
pkt_ofs
;
pp
->
hdma_prod
++
;
}
static
void
pdc20621_pop_hdma
(
struct
ata_queued_cmd
*
qc
)
{
struct
ata_port
*
ap
=
qc
->
ap
;
struct
pdc_host_priv
*
pp
=
ap
->
host_set
->
private_data
;
unsigned
int
idx
=
pp
->
hdma_cons
&
PDC_HDMA_Q_MASK
;
/* if nothing on queue, we're done */
if
(
pp
->
hdma_prod
==
pp
->
hdma_cons
)
{
pp
->
doing_hdma
=
0
;
return
;
}
__pdc20621_push_hdma
(
pp
->
hdma
[
idx
].
qc
,
pp
->
hdma
[
idx
].
seq
,
pp
->
hdma
[
idx
].
pkt_ofs
);
pp
->
hdma_cons
++
;
}
#ifdef ATA_VERBOSE_DEBUG
static
void
pdc20621_dump_hdma
(
struct
ata_queued_cmd
*
qc
)
{
struct
ata_port
*
ap
=
qc
->
ap
;
unsigned
int
port_no
=
ap
->
port_no
;
struct
pdc_host_priv
*
hpriv
=
ap
->
host_set
->
private_data
;
void
*
dimm_mmio
=
hpriv
->
dimm_mmio
;
dimm_mmio
+=
(
port_no
*
PDC_DIMM_WINDOW_STEP
);
dimm_mmio
+=
PDC_DIMM_HOST_PKT
;
printk
(
KERN_ERR
"HDMA[0] == 0x%08X
\n
"
,
readl
(
dimm_mmio
));
printk
(
KERN_ERR
"HDMA[1] == 0x%08X
\n
"
,
readl
(
dimm_mmio
+
4
));
printk
(
KERN_ERR
"HDMA[2] == 0x%08X
\n
"
,
readl
(
dimm_mmio
+
8
));
printk
(
KERN_ERR
"HDMA[3] == 0x%08X
\n
"
,
readl
(
dimm_mmio
+
12
));
}
#else
static
inline
void
pdc20621_dump_hdma
(
struct
ata_queued_cmd
*
qc
)
{
}
#endif
/* ATA_VERBOSE_DEBUG */
static
void
pdc20621_dma_start
(
struct
ata_queued_cmd
*
qc
)
{
struct
ata_port
*
ap
=
qc
->
ap
;
struct
ata_host_set
*
host_set
=
ap
->
host_set
;
unsigned
int
port_no
=
ap
->
port_no
;
void
*
mmio
=
host_set
->
mmio_base
;
unsigned
int
rw
=
(
qc
->
tf
.
flags
&
ATA_TFLAG_WRITE
);
u8
seq
=
(
u8
)
(
port_no
+
1
);
unsigned
int
doing_hdma
=
0
,
port_ofs
;
/* hard-code chip #0 */
mmio
+=
PDC_CHIP0_OFS
;
VPRINTK
(
"ata%u: ENTER
\n
"
,
ap
->
id
);
port_ofs
=
PDC_20621_DIMM_BASE
+
(
PDC_DIMM_WINDOW_STEP
*
port_no
);
/* if writing, we (1) DMA to DIMM, then (2) do ATA command */
if
(
rw
)
{
doing_hdma
=
1
;
seq
+=
4
;
}
wmb
();
/* flush PRD, pkt writes */
if
(
doing_hdma
)
{
pdc20621_dump_hdma
(
qc
);
pdc20621_push_hdma
(
qc
,
seq
,
port_ofs
+
PDC_DIMM_HOST_PKT
);
VPRINTK
(
"queued ofs 0x%x (%u), seq %u
\n
"
,
port_ofs
+
PDC_DIMM_HOST_PKT
,
port_ofs
+
PDC_DIMM_HOST_PKT
,
seq
);
}
else
{
writel
(
0x00000001
,
mmio
+
PDC_20621_SEQCTL
+
(
seq
*
4
));
readl
(
mmio
+
PDC_20621_SEQCTL
+
(
seq
*
4
));
/* flush */
writel
(
port_ofs
+
PDC_DIMM_ATA_PKT
,
(
void
*
)
ap
->
ioaddr
.
cmd_addr
+
PDC_PKT_SUBMIT
);
readl
((
void
*
)
ap
->
ioaddr
.
cmd_addr
+
PDC_PKT_SUBMIT
);
VPRINTK
(
"submitted ofs 0x%x (%u), seq %u
\n
"
,
port_ofs
+
PDC_DIMM_ATA_PKT
,
port_ofs
+
PDC_DIMM_ATA_PKT
,
seq
);
}
}
static
inline
unsigned
int
pdc20621_host_intr
(
struct
ata_port
*
ap
,
struct
ata_queued_cmd
*
qc
,
unsigned
int
doing_hdma
,
void
*
mmio
)
{
unsigned
int
port_no
=
ap
->
port_no
;
unsigned
int
port_ofs
=
PDC_20621_DIMM_BASE
+
(
PDC_DIMM_WINDOW_STEP
*
port_no
);
u8
status
;
unsigned
int
handled
=
0
;
VPRINTK
(
"ENTER
\n
"
);
if
((
qc
->
tf
.
protocol
==
ATA_PROT_DMA
)
&&
/* read */
(
!
(
qc
->
tf
.
flags
&
ATA_TFLAG_WRITE
)))
{
/* step two - DMA from DIMM to host */
if
(
doing_hdma
)
{
VPRINTK
(
"ata%u: read hdma, 0x%x 0x%x
\n
"
,
ap
->
id
,
readl
(
mmio
+
0x104
),
readl
(
mmio
+
PDC_HDMA_CTLSTAT
));
pdc_dma_complete
(
ap
,
qc
,
0
);
pdc20621_pop_hdma
(
qc
);
}
/* step one - exec ATA command */
else
{
u8
seq
=
(
u8
)
(
port_no
+
1
+
4
);
VPRINTK
(
"ata%u: read ata, 0x%x 0x%x
\n
"
,
ap
->
id
,
readl
(
mmio
+
0x104
),
readl
(
mmio
+
PDC_HDMA_CTLSTAT
));
/* submit hdma pkt */
pdc20621_dump_hdma
(
qc
);
pdc20621_push_hdma
(
qc
,
seq
,
port_ofs
+
PDC_DIMM_HOST_PKT
);
}
handled
=
1
;
}
else
if
(
qc
->
tf
.
protocol
==
ATA_PROT_DMA
)
{
/* write */
/* step one - DMA from host to DIMM */
if
(
doing_hdma
)
{
u8
seq
=
(
u8
)
(
port_no
+
1
);
VPRINTK
(
"ata%u: write hdma, 0x%x 0x%x
\n
"
,
ap
->
id
,
readl
(
mmio
+
0x104
),
readl
(
mmio
+
PDC_HDMA_CTLSTAT
));
/* submit ata pkt */
writel
(
0x00000001
,
mmio
+
PDC_20621_SEQCTL
+
(
seq
*
4
));
readl
(
mmio
+
PDC_20621_SEQCTL
+
(
seq
*
4
));
writel
(
port_ofs
+
PDC_DIMM_ATA_PKT
,
(
void
*
)
ap
->
ioaddr
.
cmd_addr
+
PDC_PKT_SUBMIT
);
readl
((
void
*
)
ap
->
ioaddr
.
cmd_addr
+
PDC_PKT_SUBMIT
);
}
/* step two - execute ATA command */
else
{
VPRINTK
(
"ata%u: write ata, 0x%x 0x%x
\n
"
,
ap
->
id
,
readl
(
mmio
+
0x104
),
readl
(
mmio
+
PDC_HDMA_CTLSTAT
));
pdc_dma_complete
(
ap
,
qc
,
0
);
pdc20621_pop_hdma
(
qc
);
}
handled
=
1
;
/* command completion, but no data xfer */
}
else
if
(
qc
->
tf
.
protocol
==
ATA_PROT_NODATA
)
{
status
=
ata_busy_wait
(
ap
,
ATA_BUSY
|
ATA_DRQ
,
1000
);
DPRINTK
(
"BUS_NODATA (drv_stat 0x%X)
\n
"
,
status
);
ata_qc_complete
(
qc
,
status
,
0
);
handled
=
1
;
}
else
{
ap
->
stats
.
idle_irq
++
;
}
return
handled
;
}
static
irqreturn_t
pdc20621_interrupt
(
int
irq
,
void
*
dev_instance
,
struct
pt_regs
*
regs
)
{
struct
ata_host_set
*
host_set
=
dev_instance
;
struct
ata_port
*
ap
;
u32
mask
=
0
;
unsigned
int
i
,
tmp
,
port_no
;
unsigned
int
handled
=
0
;
void
*
mmio_base
;
VPRINTK
(
"ENTER
\n
"
);
if
(
!
host_set
||
!
host_set
->
mmio_base
)
{
VPRINTK
(
"QUICK EXIT
\n
"
);
return
IRQ_NONE
;
}
mmio_base
=
host_set
->
mmio_base
;
/* reading should also clear interrupts */
mmio_base
+=
PDC_CHIP0_OFS
;
mask
=
readl
(
mmio_base
+
PDC_20621_SEQMASK
);
VPRINTK
(
"mask == 0x%x
\n
"
,
mask
);
if
(
mask
==
0xffffffff
)
{
VPRINTK
(
"QUICK EXIT 2
\n
"
);
return
IRQ_NONE
;
}
mask
&=
0xffff
;
/* only 16 tags possible */
if
(
!
mask
)
{
VPRINTK
(
"QUICK EXIT 3
\n
"
);
return
IRQ_NONE
;
}
spin_lock
(
&
host_set
->
lock
);
for
(
i
=
1
;
i
<
9
;
i
++
)
{
port_no
=
i
-
1
;
if
(
port_no
>
3
)
port_no
-=
4
;
if
(
port_no
>=
host_set
->
n_ports
)
ap
=
NULL
;
else
ap
=
host_set
->
ports
[
port_no
];
tmp
=
mask
&
(
1
<<
i
);
VPRINTK
(
"seq %u, port_no %u, ap %p, tmp %x
\n
"
,
i
,
port_no
,
ap
,
tmp
);
if
(
tmp
&&
ap
&&
(
!
(
ap
->
flags
&
ATA_FLAG_PORT_DISABLED
)))
{
struct
ata_queued_cmd
*
qc
;
qc
=
ata_qc_from_tag
(
ap
,
ap
->
active_tag
);
if
(
qc
&&
((
qc
->
flags
&
ATA_QCFLAG_POLL
)
==
0
))
handled
+=
pdc20621_host_intr
(
ap
,
qc
,
(
i
>
4
),
mmio_base
);
}
}
spin_unlock
(
&
host_set
->
lock
);
VPRINTK
(
"mask == 0x%x
\n
"
,
mask
);
VPRINTK
(
"EXIT
\n
"
);
return
IRQ_RETVAL
(
handled
);
}
static
void
pdc_fill_sg
(
struct
ata_queued_cmd
*
qc
)
{
struct
pdc_port_priv
*
pp
=
qc
->
ap
->
private_data
;
unsigned
int
i
;
VPRINTK
(
"ENTER
\n
"
);
ata_fill_sg
(
qc
);
i
=
pdc_pkt_header
(
&
qc
->
tf
,
qc
->
ap
->
prd_dma
,
qc
->
dev
->
devno
,
pp
->
pkt
);
if
(
qc
->
tf
.
flags
&
ATA_TFLAG_LBA48
)
i
=
pdc_prep_lba48
(
&
qc
->
tf
,
pp
->
pkt
,
i
);
else
i
=
pdc_prep_lba28
(
&
qc
->
tf
,
pp
->
pkt
,
i
);
pdc_pkt_footer
(
&
qc
->
tf
,
pp
->
pkt
,
i
);
}
static
inline
void
pdc_dma_complete
(
struct
ata_port
*
ap
,
struct
ata_queued_cmd
*
qc
,
int
have_err
)
{
u8
err_bit
=
have_err
?
ATA_ERR
:
0
;
/* get drive status; clear intr; complete txn */
ata_qc_complete
(
ata_qc_from_tag
(
ap
,
ap
->
active_tag
),
ata_wait_idle
(
ap
)
|
err_bit
,
0
);
}
static
void
pdc_eng_timeout
(
struct
ata_port
*
ap
)
{
u8
drv_stat
;
struct
ata_queued_cmd
*
qc
;
DPRINTK
(
"ENTER
\n
"
);
qc
=
ata_qc_from_tag
(
ap
,
ap
->
active_tag
);
if
(
!
qc
)
{
printk
(
KERN_ERR
"ata%u: BUG: timeout without command
\n
"
,
ap
->
id
);
goto
out
;
}
/* hack alert! We cannot use the supplied completion
* function from inside the ->eh_strategy_handler() thread.
* libata is the only user of ->eh_strategy_handler() in
* any kernel, so the default scsi_done() assumes it is
* not being called from the SCSI EH.
*/
qc
->
scsidone
=
scsi_finish_command
;
switch
(
qc
->
tf
.
protocol
)
{
case
ATA_PROT_DMA
:
printk
(
KERN_ERR
"ata%u: DMA timeout
\n
"
,
ap
->
id
);
ata_qc_complete
(
ata_qc_from_tag
(
ap
,
ap
->
active_tag
),
ata_wait_idle
(
ap
)
|
ATA_ERR
,
0
);
break
;
case
ATA_PROT_NODATA
:
drv_stat
=
ata_busy_wait
(
ap
,
ATA_BUSY
|
ATA_DRQ
,
1000
);
printk
(
KERN_ERR
"ata%u: command 0x%x timeout, stat 0x%x
\n
"
,
ap
->
id
,
qc
->
tf
.
command
,
drv_stat
);
ata_qc_complete
(
qc
,
drv_stat
,
1
);
break
;
default:
drv_stat
=
ata_busy_wait
(
ap
,
ATA_BUSY
|
ATA_DRQ
,
1000
);
printk
(
KERN_ERR
"ata%u: unknown timeout, cmd 0x%x stat 0x%x
\n
"
,
ap
->
id
,
qc
->
tf
.
command
,
drv_stat
);
ata_qc_complete
(
qc
,
drv_stat
,
1
);
break
;
}
out:
DPRINTK
(
"EXIT
\n
"
);
}
static
inline
unsigned
int
pdc_host_intr
(
struct
ata_port
*
ap
,
struct
ata_queued_cmd
*
qc
)
{
u8
status
;
unsigned
int
handled
=
0
,
have_err
=
0
;
u32
tmp
;
void
*
mmio
=
(
void
*
)
ap
->
ioaddr
.
cmd_addr
+
PDC_GLOBAL_CTL
;
tmp
=
readl
(
mmio
);
if
(
tmp
&
PDC_ERR_MASK
)
{
have_err
=
1
;
pdc_reset_port
(
ap
);
}
switch
(
qc
->
tf
.
protocol
)
{
case
ATA_PROT_DMA
:
pdc_dma_complete
(
ap
,
qc
,
have_err
);
handled
=
1
;
break
;
case
ATA_PROT_NODATA
:
/* command completion, but no data xfer */
status
=
ata_busy_wait
(
ap
,
ATA_BUSY
|
ATA_DRQ
,
1000
);
DPRINTK
(
"BUS_NODATA (drv_stat 0x%X)
\n
"
,
status
);
if
(
have_err
)
status
|=
ATA_ERR
;
ata_qc_complete
(
qc
,
status
,
0
);
handled
=
1
;
break
;
default:
ap
->
stats
.
idle_irq
++
;
break
;
}
return
handled
;
}
static
irqreturn_t
pdc_interrupt
(
int
irq
,
void
*
dev_instance
,
struct
pt_regs
*
regs
)
{
struct
ata_host_set
*
host_set
=
dev_instance
;
struct
ata_port
*
ap
;
u32
mask
=
0
;
unsigned
int
i
,
tmp
;
unsigned
int
handled
=
0
;
void
*
mmio_base
;
VPRINTK
(
"ENTER
\n
"
);
if
(
!
host_set
||
!
host_set
->
mmio_base
)
{
VPRINTK
(
"QUICK EXIT
\n
"
);
return
IRQ_NONE
;
}
mmio_base
=
host_set
->
mmio_base
;
/* reading should also clear interrupts */
mask
=
readl
(
mmio_base
+
PDC_INT_SEQMASK
);
if
(
mask
==
0xffffffff
)
{
VPRINTK
(
"QUICK EXIT 2
\n
"
);
return
IRQ_NONE
;
}
mask
&=
0xffff
;
/* only 16 tags possible */
if
(
!
mask
)
{
VPRINTK
(
"QUICK EXIT 3
\n
"
);
return
IRQ_NONE
;
}
spin_lock
(
&
host_set
->
lock
);
for
(
i
=
0
;
i
<
host_set
->
n_ports
;
i
++
)
{
VPRINTK
(
"port %u
\n
"
,
i
);
ap
=
host_set
->
ports
[
i
];
tmp
=
mask
&
(
1
<<
(
i
+
1
));
if
(
tmp
&&
ap
&&
(
!
(
ap
->
flags
&
ATA_FLAG_PORT_DISABLED
)))
{
struct
ata_queued_cmd
*
qc
;
qc
=
ata_qc_from_tag
(
ap
,
ap
->
active_tag
);
if
(
qc
&&
((
qc
->
flags
&
ATA_QCFLAG_POLL
)
==
0
))
handled
+=
pdc_host_intr
(
ap
,
qc
);
}
}
spin_unlock
(
&
host_set
->
lock
);
VPRINTK
(
"EXIT
\n
"
);
return
IRQ_RETVAL
(
handled
);
}
static
void
pdc_dma_start
(
struct
ata_queued_cmd
*
qc
)
{
struct
ata_port
*
ap
=
qc
->
ap
;
struct
pdc_port_priv
*
pp
=
ap
->
private_data
;
unsigned
int
port_no
=
ap
->
port_no
;
u8
seq
=
(
u8
)
(
port_no
+
1
);
VPRINTK
(
"ENTER, ap %p
\n
"
,
ap
);
writel
(
0x00000001
,
ap
->
host_set
->
mmio_base
+
(
seq
*
4
));
readl
(
ap
->
host_set
->
mmio_base
+
(
seq
*
4
));
/* flush */
pp
->
pkt
[
2
]
=
seq
;
wmb
();
/* flush PRD, pkt writes */
writel
(
pp
->
pkt_dma
,
(
void
*
)
ap
->
ioaddr
.
cmd_addr
+
PDC_PKT_SUBMIT
);
readl
((
void
*
)
ap
->
ioaddr
.
cmd_addr
+
PDC_PKT_SUBMIT
);
/* flush */
}
static
void
pdc_tf_load_mmio
(
struct
ata_port
*
ap
,
struct
ata_taskfile
*
tf
)
{
if
(
tf
->
protocol
==
ATA_PROT_PIO
)
ata_tf_load_mmio
(
ap
,
tf
);
}
static
void
pdc_exec_command_mmio
(
struct
ata_port
*
ap
,
struct
ata_taskfile
*
tf
)
{
if
(
tf
->
protocol
==
ATA_PROT_PIO
)
ata_exec_command_mmio
(
ap
,
tf
);
}
static
void
pdc_sata_setup_port
(
struct
ata_ioports
*
port
,
unsigned
long
base
)
{
port
->
cmd_addr
=
base
;
port
->
data_addr
=
base
;
port
->
feature_addr
=
port
->
error_addr
=
base
+
0x4
;
port
->
nsect_addr
=
base
+
0x8
;
port
->
lbal_addr
=
base
+
0xc
;
port
->
lbam_addr
=
base
+
0x10
;
port
->
lbah_addr
=
base
+
0x14
;
port
->
device_addr
=
base
+
0x18
;
port
->
command_addr
=
port
->
status_addr
=
base
+
0x1c
;
port
->
altstatus_addr
=
port
->
ctl_addr
=
base
+
0x38
;
}
#ifdef ATA_VERBOSE_DEBUG
static
void
pdc20621_get_from_dimm
(
struct
ata_probe_ent
*
pe
,
void
*
psource
,
u32
offset
,
u32
size
)
{
u32
window_size
;
u16
idx
;
u8
page_mask
;
long
dist
;
void
*
mmio
=
pe
->
mmio_base
;
struct
pdc_host_priv
*
hpriv
=
pe
->
private_data
;
void
*
dimm_mmio
=
hpriv
->
dimm_mmio
;
/* hard-code chip #0 */
mmio
+=
PDC_CHIP0_OFS
;
page_mask
=
0x00
;
window_size
=
0x2000
*
4
;
/* 32K byte uchar size */
idx
=
(
u16
)
(
offset
/
window_size
);
writel
(
0x01
,
mmio
+
PDC_GENERAL_CTLR
);
readl
(
mmio
+
PDC_GENERAL_CTLR
);
writel
(((
idx
)
<<
page_mask
),
mmio
+
PDC_DIMM_WINDOW_CTLR
);
readl
(
mmio
+
PDC_DIMM_WINDOW_CTLR
);
offset
-=
(
idx
*
window_size
);
idx
++
;
dist
=
((
long
)
(
window_size
-
(
offset
+
size
)))
>=
0
?
size
:
(
long
)
(
window_size
-
offset
);
memcpy_fromio
((
char
*
)
psource
,
(
char
*
)
(
dimm_mmio
+
offset
/
4
),
dist
);
psource
+=
dist
;
size
-=
dist
;
for
(;
(
long
)
size
>=
(
long
)
window_size
;)
{
writel
(
0x01
,
mmio
+
PDC_GENERAL_CTLR
);
readl
(
mmio
+
PDC_GENERAL_CTLR
);
writel
(((
idx
)
<<
page_mask
),
mmio
+
PDC_DIMM_WINDOW_CTLR
);
readl
(
mmio
+
PDC_DIMM_WINDOW_CTLR
);
memcpy_fromio
((
char
*
)
psource
,
(
char
*
)
(
dimm_mmio
),
window_size
/
4
);
psource
+=
window_size
;
size
-=
window_size
;
idx
++
;
}
if
(
size
)
{
writel
(
0x01
,
mmio
+
PDC_GENERAL_CTLR
);
readl
(
mmio
+
PDC_GENERAL_CTLR
);
writel
(((
idx
)
<<
page_mask
),
mmio
+
PDC_DIMM_WINDOW_CTLR
);
readl
(
mmio
+
PDC_DIMM_WINDOW_CTLR
);
memcpy_fromio
((
char
*
)
psource
,
(
char
*
)
(
dimm_mmio
),
size
/
4
);
}
}
#endif
static
void
pdc20621_put_to_dimm
(
struct
ata_probe_ent
*
pe
,
void
*
psource
,
u32
offset
,
u32
size
)
{
u32
window_size
;
u16
idx
;
u8
page_mask
;
long
dist
;
void
*
mmio
=
pe
->
mmio_base
;
struct
pdc_host_priv
*
hpriv
=
pe
->
private_data
;
void
*
dimm_mmio
=
hpriv
->
dimm_mmio
;
/* hard-code chip #0 */
mmio
+=
PDC_CHIP0_OFS
;
page_mask
=
0x00
;
window_size
=
0x2000
*
4
;
/* 32K byte uchar size */
idx
=
(
u16
)
(
offset
/
window_size
);
writel
(((
idx
)
<<
page_mask
),
mmio
+
PDC_DIMM_WINDOW_CTLR
);
readl
(
mmio
+
PDC_DIMM_WINDOW_CTLR
);
offset
-=
(
idx
*
window_size
);
idx
++
;
dist
=
((
long
)
(
window_size
-
(
offset
+
size
)))
>=
0
?
size
:
(
long
)
(
window_size
-
offset
);
memcpy_toio
((
char
*
)
(
dimm_mmio
+
offset
/
4
),
(
char
*
)
psource
,
dist
);
writel
(
0x01
,
mmio
+
PDC_GENERAL_CTLR
);
readl
(
mmio
+
PDC_GENERAL_CTLR
);
psource
+=
dist
;
size
-=
dist
;
for
(;
(
long
)
size
>=
(
long
)
window_size
;)
{
writel
(((
idx
)
<<
page_mask
),
mmio
+
PDC_DIMM_WINDOW_CTLR
);
readl
(
mmio
+
PDC_DIMM_WINDOW_CTLR
);
memcpy_toio
((
char
*
)
(
dimm_mmio
),
(
char
*
)
psource
,
window_size
/
4
);
writel
(
0x01
,
mmio
+
PDC_GENERAL_CTLR
);
readl
(
mmio
+
PDC_GENERAL_CTLR
);
psource
+=
window_size
;
size
-=
window_size
;
idx
++
;
}
if
(
size
)
{
writel
(((
idx
)
<<
page_mask
),
mmio
+
PDC_DIMM_WINDOW_CTLR
);
readl
(
mmio
+
PDC_DIMM_WINDOW_CTLR
);
memcpy_toio
((
char
*
)
(
dimm_mmio
),
(
char
*
)
psource
,
size
/
4
);
writel
(
0x01
,
mmio
+
PDC_GENERAL_CTLR
);
readl
(
mmio
+
PDC_GENERAL_CTLR
);
}
}
static
unsigned
int
pdc20621_i2c_read
(
struct
ata_probe_ent
*
pe
,
u32
device
,
u32
subaddr
,
u32
*
pdata
)
{
void
*
mmio
=
pe
->
mmio_base
;
u32
i2creg
=
0
;
u32
status
;
u32
count
=
0
;
/* hard-code chip #0 */
mmio
+=
PDC_CHIP0_OFS
;
i2creg
|=
device
<<
24
;
i2creg
|=
subaddr
<<
16
;
/* Set the device and subaddress */
writel
(
i2creg
,
mmio
+
PDC_I2C_ADDR_DATA_OFFSET
);
readl
(
mmio
+
PDC_I2C_ADDR_DATA_OFFSET
);
/* Write Control to perform read operation, mask int */
writel
(
PDC_I2C_READ
|
PDC_I2C_START
|
PDC_I2C_MASK_INT
,
mmio
+
PDC_I2C_CONTROL_OFFSET
);
for
(
count
=
0
;
count
<=
1000
;
count
++
)
{
status
=
readl
(
mmio
+
PDC_I2C_CONTROL_OFFSET
);
if
(
status
&
PDC_I2C_COMPLETE
)
{
status
=
readl
(
mmio
+
PDC_I2C_ADDR_DATA_OFFSET
);
break
;
}
else
if
(
count
==
1000
)
return
0
;
}
*
pdata
=
(
status
>>
8
)
&
0x000000ff
;
return
1
;
}
static
int
pdc20621_detect_dimm
(
struct
ata_probe_ent
*
pe
)
{
u32
data
=
0
;
if
(
pdc20621_i2c_read
(
pe
,
PDC_DIMM0_SPD_DEV_ADDRESS
,
PDC_DIMM_SPD_SYSTEM_FREQ
,
&
data
))
{
if
(
data
==
100
)
return
100
;
}
else
return
0
;
if
(
pdc20621_i2c_read
(
pe
,
PDC_DIMM0_SPD_DEV_ADDRESS
,
9
,
&
data
))
{
if
(
data
<=
0x75
)
return
133
;
}
else
return
0
;
return
0
;
}
static
int
pdc20621_prog_dimm0
(
struct
ata_probe_ent
*
pe
)
{
u32
spd0
[
50
];
u32
data
=
0
;
int
size
,
i
;
u8
bdimmsize
;
void
*
mmio
=
pe
->
mmio_base
;
static
const
struct
{
unsigned
int
reg
;
unsigned
int
ofs
;
}
pdc_i2c_read_data
[]
=
{
{
PDC_DIMM_SPD_TYPE
,
11
},
{
PDC_DIMM_SPD_FRESH_RATE
,
12
},
{
PDC_DIMM_SPD_COLUMN_NUM
,
4
},
{
PDC_DIMM_SPD_ATTRIBUTE
,
21
},
{
PDC_DIMM_SPD_ROW_NUM
,
3
},
{
PDC_DIMM_SPD_BANK_NUM
,
17
},
{
PDC_DIMM_SPD_MODULE_ROW
,
5
},
{
PDC_DIMM_SPD_ROW_PRE_CHARGE
,
27
},
{
PDC_DIMM_SPD_ROW_ACTIVE_DELAY
,
28
},
{
PDC_DIMM_SPD_RAS_CAS_DELAY
,
29
},
{
PDC_DIMM_SPD_ACTIVE_PRECHARGE
,
30
},
{
PDC_DIMM_SPD_CAS_LATENCY
,
18
},
};
/* hard-code chip #0 */
mmio
+=
PDC_CHIP0_OFS
;
for
(
i
=
0
;
i
<
ARRAY_SIZE
(
pdc_i2c_read_data
);
i
++
)
pdc20621_i2c_read
(
pe
,
PDC_DIMM0_SPD_DEV_ADDRESS
,
pdc_i2c_read_data
[
i
].
reg
,
&
spd0
[
pdc_i2c_read_data
[
i
].
ofs
]);
data
|=
(
spd0
[
4
]
-
8
)
|
((
spd0
[
21
]
!=
0
)
<<
3
)
|
((
spd0
[
3
]
-
11
)
<<
4
);
data
|=
((
spd0
[
17
]
/
4
)
<<
6
)
|
((
spd0
[
5
]
/
2
)
<<
7
)
|
((((
spd0
[
27
]
+
9
)
/
10
)
-
1
)
<<
8
)
;
data
|=
(((((
spd0
[
29
]
>
spd0
[
28
])
?
spd0
[
29
]
:
spd0
[
28
])
+
9
)
/
10
)
-
1
)
<<
10
;
data
|=
((
spd0
[
30
]
-
spd0
[
29
]
+
9
)
/
10
-
2
)
<<
12
;
if
(
spd0
[
18
]
&
0x08
)
data
|=
((
0x03
)
<<
14
);
else
if
(
spd0
[
18
]
&
0x04
)
data
|=
((
0x02
)
<<
14
);
else
if
(
spd0
[
18
]
&
0x01
)
data
|=
((
0x01
)
<<
14
);
else
data
|=
(
0
<<
14
);
/*
Calculate the size of bDIMMSize (power of 2) and
merge the DIMM size by program start/end address.
*/
bdimmsize
=
spd0
[
4
]
+
(
spd0
[
5
]
/
2
)
+
spd0
[
3
]
+
(
spd0
[
17
]
/
2
)
+
3
;
size
=
(
1
<<
bdimmsize
)
>>
20
;
/* size = xxx(MB) */
data
|=
(((
size
/
16
)
-
1
)
<<
16
);
data
|=
(
0
<<
23
);
data
|=
8
;
writel
(
data
,
mmio
+
PDC_DIMM0_CONTROL_OFFSET
);
readl
(
mmio
+
PDC_DIMM0_CONTROL_OFFSET
);
return
size
;
}
static
unsigned
int
pdc20621_prog_dimm_global
(
struct
ata_probe_ent
*
pe
)
{
u32
data
,
spd0
;
int
error
,
i
;
void
*
mmio
=
pe
->
mmio_base
;
/* hard-code chip #0 */
mmio
+=
PDC_CHIP0_OFS
;
/*
Set To Default : DIMM Module Global Control Register (0x022259F1)
DIMM Arbitration Disable (bit 20)
DIMM Data/Control Output Driving Selection (bit12 - bit15)
Refresh Enable (bit 17)
*/
data
=
0x022259F1
;
writel
(
data
,
mmio
+
PDC_SDRAM_CONTROL_OFFSET
);
readl
(
mmio
+
PDC_SDRAM_CONTROL_OFFSET
);
/* Turn on for ECC */
pdc20621_i2c_read
(
pe
,
PDC_DIMM0_SPD_DEV_ADDRESS
,
PDC_DIMM_SPD_TYPE
,
&
spd0
);
if
(
spd0
==
0x02
)
{
data
|=
(
0x01
<<
16
);
writel
(
data
,
mmio
+
PDC_SDRAM_CONTROL_OFFSET
);
readl
(
mmio
+
PDC_SDRAM_CONTROL_OFFSET
);
printk
(
KERN_ERR
"Local DIMM ECC Enabled
\n
"
);
}
/* DIMM Initialization Select/Enable (bit 18/19) */
data
&=
(
~
(
1
<<
18
));
data
|=
(
1
<<
19
);
writel
(
data
,
mmio
+
PDC_SDRAM_CONTROL_OFFSET
);
error
=
1
;
for
(
i
=
1
;
i
<=
10
;
i
++
)
{
/* polling ~5 secs */
data
=
readl
(
mmio
+
PDC_SDRAM_CONTROL_OFFSET
);
if
(
!
(
data
&
(
1
<<
19
)))
{
error
=
0
;
break
;
}
set_current_state
(
TASK_INTERRUPTIBLE
);
schedule_timeout
((
i
*
100
)
*
HZ
/
1000
);
}
return
error
;
}
static
unsigned
int
pdc20621_dimm_init
(
struct
ata_probe_ent
*
pe
)
{
int
speed
,
size
,
length
;
u32
addr
,
spd0
,
pci_status
;
u32
tmp
=
0
;
u32
time_period
=
0
;
u32
tcount
=
0
;
u32
ticks
=
0
;
u32
clock
=
0
;
u32
fparam
=
0
;
void
*
mmio
=
pe
->
mmio_base
;
/* hard-code chip #0 */
mmio
+=
PDC_CHIP0_OFS
;
/* Initialize PLL based upon PCI Bus Frequency */
/* Initialize Time Period Register */
writel
(
0xffffffff
,
mmio
+
PDC_TIME_PERIOD
);
time_period
=
readl
(
mmio
+
PDC_TIME_PERIOD
);
VPRINTK
(
"Time Period Register (0x40): 0x%x
\n
"
,
time_period
);
/* Enable timer */
writel
(
0x00001a0
,
mmio
+
PDC_TIME_CONTROL
);
readl
(
mmio
+
PDC_TIME_CONTROL
);
/* Wait 3 seconds */
set_current_state
(
TASK_UNINTERRUPTIBLE
);
schedule_timeout
(
3
*
HZ
);
/*
When timer is enabled, counter is decreased every internal
clock cycle.
*/
tcount
=
readl
(
mmio
+
PDC_TIME_COUNTER
);
VPRINTK
(
"Time Counter Register (0x44): 0x%x
\n
"
,
tcount
);
/*
If SX4 is on PCI-X bus, after 3 seconds, the timer counter
register should be >= (0xffffffff - 3x10^8).
*/
if
(
tcount
>=
PCI_X_TCOUNT
)
{
ticks
=
(
time_period
-
tcount
);
VPRINTK
(
"Num counters 0x%x (%d)
\n
"
,
ticks
,
ticks
);
clock
=
(
ticks
/
300000
);
VPRINTK
(
"10 * Internal clk = 0x%x (%d)
\n
"
,
clock
,
clock
);
clock
=
(
clock
*
33
);
VPRINTK
(
"10 * Internal clk * 33 = 0x%x (%d)
\n
"
,
clock
,
clock
);
/* PLL F Param (bit 22:16) */
fparam
=
(
1400000
/
clock
)
-
2
;
VPRINTK
(
"PLL F Param: 0x%x (%d)
\n
"
,
fparam
,
fparam
);
/* OD param = 0x2 (bit 31:30), R param = 0x5 (bit 29:25) */
pci_status
=
(
0x8a001824
|
(
fparam
<<
16
));
}
else
pci_status
=
PCI_PLL_INIT
;
/* Initialize PLL. */
VPRINTK
(
"pci_status: 0x%x
\n
"
,
pci_status
);
writel
(
pci_status
,
mmio
+
PDC_CTL_STATUS
);
readl
(
mmio
+
PDC_CTL_STATUS
);
/*
Read SPD of DIMM by I2C interface,
and program the DIMM Module Controller.
*/
if
(
!
(
speed
=
pdc20621_detect_dimm
(
pe
)))
{
printk
(
KERN_ERR
"Detect Local DIMM Fail
\n
"
);
return
1
;
/* DIMM error */
}
VPRINTK
(
"Local DIMM Speed = %d
\n
"
,
speed
);
/* Programming DIMM0 Module Control Register (index_CID0:80h) */
size
=
pdc20621_prog_dimm0
(
pe
);
VPRINTK
(
"Local DIMM Size = %dMB
\n
"
,
size
);
/* Programming DIMM Module Global Control Register (index_CID0:88h) */
if
(
pdc20621_prog_dimm_global
(
pe
))
{
printk
(
KERN_ERR
"Programming DIMM Module Global Control Register Fail
\n
"
);
return
1
;
}
#ifdef ATA_VERBOSE_DEBUG
{
u8
test_parttern1
[
40
]
=
{
0x55
,
0xAA
,
'P'
,
'r'
,
'o'
,
'm'
,
'i'
,
's'
,
'e'
,
' '
,
'N'
,
'o'
,
't'
,
' '
,
'Y'
,
'e'
,
't'
,
' '
,
'D'
,
'e'
,
'f'
,
'i'
,
'n'
,
'e'
,
'd'
,
' '
,
'1'
,
'.'
,
'1'
,
'0'
,
'9'
,
'8'
,
'0'
,
'3'
,
'1'
,
'6'
,
'1'
,
'2'
,
0
,
0
};
u8
test_parttern2
[
40
]
=
{
0
};
pdc20621_put_to_dimm
(
pe
,
(
void
*
)
test_parttern2
,
0x10040
,
40
);
pdc20621_put_to_dimm
(
pe
,
(
void
*
)
test_parttern2
,
0x40
,
40
);
pdc20621_put_to_dimm
(
pe
,
(
void
*
)
test_parttern1
,
0x10040
,
40
);
pdc20621_get_from_dimm
(
pe
,
(
void
*
)
test_parttern2
,
0x40
,
40
);
printk
(
KERN_ERR
"%x, %x, %s
\n
"
,
test_parttern2
[
0
],
test_parttern2
[
1
],
&
(
test_parttern2
[
2
]));
pdc20621_get_from_dimm
(
pe
,
(
void
*
)
test_parttern2
,
0x10040
,
40
);
printk
(
KERN_ERR
"%x, %x, %s
\n
"
,
test_parttern2
[
0
],
test_parttern2
[
1
],
&
(
test_parttern2
[
2
]));
pdc20621_put_to_dimm
(
pe
,
(
void
*
)
test_parttern1
,
0x40
,
40
);
pdc20621_get_from_dimm
(
pe
,
(
void
*
)
test_parttern2
,
0x40
,
40
);
printk
(
KERN_ERR
"%x, %x, %s
\n
"
,
test_parttern2
[
0
],
test_parttern2
[
1
],
&
(
test_parttern2
[
2
]));
}
#endif
/* ECC initiliazation. */
pdc20621_i2c_read
(
pe
,
PDC_DIMM0_SPD_DEV_ADDRESS
,
PDC_DIMM_SPD_TYPE
,
&
spd0
);
if
(
spd0
==
0x02
)
{
VPRINTK
(
"Start ECC initialization
\n
"
);
addr
=
0
;
length
=
size
*
1024
*
1024
;
while
(
addr
<
length
)
{
pdc20621_put_to_dimm
(
pe
,
(
void
*
)
&
tmp
,
addr
,
sizeof
(
u32
));
addr
+=
sizeof
(
u32
);
}
VPRINTK
(
"Finish ECC initialization
\n
"
);
}
return
0
;
}
static
void
pdc_20621_init
(
struct
ata_probe_ent
*
pe
)
{
u32
tmp
;
void
*
mmio
=
pe
->
mmio_base
;
/* hard-code chip #0 */
mmio
+=
PDC_CHIP0_OFS
;
/*
* Select page 0x40 for our 32k DIMM window
*/
tmp
=
readl
(
mmio
+
PDC_20621_DIMM_WINDOW
)
&
0xffff0000
;
tmp
|=
PDC_PAGE_WINDOW
;
/* page 40h; arbitrarily selected */
writel
(
tmp
,
mmio
+
PDC_20621_DIMM_WINDOW
);
/*
* Reset Host DMA
*/
tmp
=
readl
(
mmio
+
PDC_HDMA_CTLSTAT
);
tmp
|=
PDC_RESET
;
writel
(
tmp
,
mmio
+
PDC_HDMA_CTLSTAT
);
readl
(
mmio
+
PDC_HDMA_CTLSTAT
);
/* flush */
udelay
(
10
);
tmp
=
readl
(
mmio
+
PDC_HDMA_CTLSTAT
);
tmp
&=
~
PDC_RESET
;
writel
(
tmp
,
mmio
+
PDC_HDMA_CTLSTAT
);
readl
(
mmio
+
PDC_HDMA_CTLSTAT
);
/* flush */
}
static
void
pdc_host_init
(
unsigned
int
chip_id
,
struct
ata_probe_ent
*
pe
)
{
void
*
mmio
=
pe
->
mmio_base
;
u32
tmp
;
if
(
chip_id
==
board_20621
)
BUG
();
/*
* Except for the hotplug stuff, this is voodoo from the
* Promise driver. Label this entire section
* "TODO: figure out why we do this"
*/
/* change FIFO_SHD to 8 dwords, enable BMR_BURST */
tmp
=
readl
(
mmio
+
PDC_FLASH_CTL
);
tmp
|=
0x12000
;
/* bit 16 (fifo 8 dw) and 13 (bmr burst?) */
writel
(
tmp
,
mmio
+
PDC_FLASH_CTL
);
/* clear plug/unplug flags for all ports */
tmp
=
readl
(
mmio
+
PDC_SATA_PLUG_CSR
);
writel
(
tmp
|
0xff
,
mmio
+
PDC_SATA_PLUG_CSR
);
/* mask plug/unplug ints */
tmp
=
readl
(
mmio
+
PDC_SATA_PLUG_CSR
);
writel
(
tmp
|
0xff0000
,
mmio
+
PDC_SATA_PLUG_CSR
);
/* reduce TBG clock to 133 Mhz. */
tmp
=
readl
(
mmio
+
PDC_TBG_MODE
);
tmp
&=
~
0x30000
;
/* clear bit 17, 16*/
tmp
|=
0x10000
;
/* set bit 17:16 = 0:1 */
writel
(
tmp
,
mmio
+
PDC_TBG_MODE
);
readl
(
mmio
+
PDC_TBG_MODE
);
/* flush */
set_current_state
(
TASK_UNINTERRUPTIBLE
);
schedule_timeout
(
msecs_to_jiffies
(
10
));
/* adjust slew rate control register. */
tmp
=
readl
(
mmio
+
PDC_SLEW_CTL
);
tmp
&=
0xFFFFF03F
;
/* clear bit 11 ~ 6 */
tmp
|=
0x00000900
;
/* set bit 11-9 = 100b , bit 8-6 = 100 */
writel
(
tmp
,
mmio
+
PDC_SLEW_CTL
);
}
static
int
pdc_sata_init_one
(
struct
pci_dev
*
pdev
,
const
struct
pci_device_id
*
ent
)
{
static
int
printed_version
;
struct
ata_probe_ent
*
probe_ent
=
NULL
;
unsigned
long
base
;
void
*
mmio_base
,
*
dimm_mmio
=
NULL
;
struct
pdc_host_priv
*
hpriv
=
NULL
;
unsigned
int
board_idx
=
(
unsigned
int
)
ent
->
driver_data
;
unsigned
int
have_20621
=
(
board_idx
==
board_20621
);
int
rc
;
if
(
!
printed_version
++
)
printk
(
KERN_DEBUG
DRV_NAME
" version "
DRV_VERSION
"
\n
"
);
/*
* If this driver happens to only be useful on Apple's K2, then
* we should check that here as it has a normal Serverworks ID
*/
rc
=
pci_enable_device
(
pdev
);
if
(
rc
)
return
rc
;
rc
=
pci_request_regions
(
pdev
,
DRV_NAME
);
if
(
rc
)
goto
err_out
;
rc
=
pci_set_dma_mask
(
pdev
,
ATA_DMA_MASK
);
if
(
rc
)
goto
err_out_regions
;
rc
=
pci_set_consistent_dma_mask
(
pdev
,
ATA_DMA_MASK
);
if
(
rc
)
goto
err_out_regions
;
probe_ent
=
kmalloc
(
sizeof
(
*
probe_ent
),
GFP_KERNEL
);
if
(
probe_ent
==
NULL
)
{
rc
=
-
ENOMEM
;
goto
err_out_regions
;
}
memset
(
probe_ent
,
0
,
sizeof
(
*
probe_ent
));
probe_ent
->
pdev
=
pdev
;
INIT_LIST_HEAD
(
&
probe_ent
->
node
);
mmio_base
=
ioremap
(
pci_resource_start
(
pdev
,
3
),
pci_resource_len
(
pdev
,
3
));
if
(
mmio_base
==
NULL
)
{
rc
=
-
ENOMEM
;
goto
err_out_free_ent
;
}
base
=
(
unsigned
long
)
mmio_base
;
if
(
have_20621
)
{
hpriv
=
kmalloc
(
sizeof
(
*
hpriv
),
GFP_KERNEL
);
if
(
!
hpriv
)
{
rc
=
-
ENOMEM
;
goto
err_out_iounmap
;
}
memset
(
hpriv
,
0
,
sizeof
(
*
hpriv
));
dimm_mmio
=
ioremap
(
pci_resource_start
(
pdev
,
4
),
pci_resource_len
(
pdev
,
4
));
if
(
!
dimm_mmio
)
{
kfree
(
hpriv
);
rc
=
-
ENOMEM
;
goto
err_out_iounmap
;
}
hpriv
->
dimm_mmio
=
dimm_mmio
;
}
probe_ent
->
sht
=
pdc_port_info
[
board_idx
].
sht
;
probe_ent
->
host_flags
=
pdc_port_info
[
board_idx
].
host_flags
;
probe_ent
->
pio_mask
=
pdc_port_info
[
board_idx
].
pio_mask
;
probe_ent
->
udma_mask
=
pdc_port_info
[
board_idx
].
udma_mask
;
probe_ent
->
port_ops
=
pdc_port_info
[
board_idx
].
port_ops
;
probe_ent
->
irq
=
pdev
->
irq
;
probe_ent
->
irq_flags
=
SA_SHIRQ
;
probe_ent
->
mmio_base
=
mmio_base
;
if
(
have_20621
)
{
probe_ent
->
private_data
=
hpriv
;
base
+=
PDC_CHIP0_OFS
;
}
pdc_sata_setup_port
(
&
probe_ent
->
port
[
0
],
base
+
0x200
);
pdc_sata_setup_port
(
&
probe_ent
->
port
[
1
],
base
+
0x280
);
if
(
!
have_20621
)
{
probe_ent
->
port
[
0
].
scr_addr
=
base
+
0x400
;
probe_ent
->
port
[
1
].
scr_addr
=
base
+
0x500
;
}
/* notice 4-port boards */
switch
(
board_idx
)
{
case
board_20319
:
case
board_20621
:
probe_ent
->
n_ports
=
4
;
pdc_sata_setup_port
(
&
probe_ent
->
port
[
2
],
base
+
0x300
);
pdc_sata_setup_port
(
&
probe_ent
->
port
[
3
],
base
+
0x380
);
if
(
!
have_20621
)
{
probe_ent
->
port
[
2
].
scr_addr
=
base
+
0x600
;
probe_ent
->
port
[
3
].
scr_addr
=
base
+
0x700
;
}
break
;
case
board_2037x
:
probe_ent
->
n_ports
=
2
;
break
;
default:
BUG
();
break
;
}
pci_set_master
(
pdev
);
/* initialize adapter */
if
(
have_20621
)
{
/* initialize local dimm */
if
(
pdc20621_dimm_init
(
probe_ent
))
{
rc
=
-
ENOMEM
;
goto
err_out_iounmap_dimm
;
}
pdc_20621_init
(
probe_ent
);
}
else
pdc_host_init
(
board_idx
,
probe_ent
);
/* FIXME: check ata_device_add return value */
ata_device_add
(
probe_ent
);
kfree
(
probe_ent
);
return
0
;
err_out_iounmap_dimm:
/* only get to this label if 20621 */
kfree
(
hpriv
);
iounmap
(
dimm_mmio
);
err_out_iounmap:
iounmap
(
mmio_base
);
err_out_free_ent:
kfree
(
probe_ent
);
err_out_regions:
pci_release_regions
(
pdev
);
err_out:
pci_disable_device
(
pdev
);
return
rc
;
}
static
int
__init
pdc_sata_init
(
void
)
{
return
pci_module_init
(
&
pdc_sata_pci_driver
);
}
static
void
__exit
pdc_sata_exit
(
void
)
{
pci_unregister_driver
(
&
pdc_sata_pci_driver
);
}
MODULE_AUTHOR
(
"Jeff Garzik"
);
MODULE_DESCRIPTION
(
"Promise SATA low-level driver"
);
MODULE_LICENSE
(
"GPL"
);
MODULE_DEVICE_TABLE
(
pci
,
pdc_sata_pci_tbl
);
module_init
(
pdc_sata_init
);
module_exit
(
pdc_sata_exit
);
Write
Preview
Markdown
is supported
0%
Try again
or
attach a new file
Attach a file
Cancel
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Cancel
Please
register
or
sign in
to comment