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
Kirill Smelkov
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