18c2ecf20Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0-only
28c2ecf20Sopenharmony_ci/*
38c2ecf20Sopenharmony_ci * Libata driver for the highpoint 366 and 368 UDMA66 ATA controllers.
48c2ecf20Sopenharmony_ci *
58c2ecf20Sopenharmony_ci * This driver is heavily based upon:
68c2ecf20Sopenharmony_ci *
78c2ecf20Sopenharmony_ci * linux/drivers/ide/pci/hpt366.c		Version 0.36	April 25, 2003
88c2ecf20Sopenharmony_ci *
98c2ecf20Sopenharmony_ci * Copyright (C) 1999-2003		Andre Hedrick <andre@linux-ide.org>
108c2ecf20Sopenharmony_ci * Portions Copyright (C) 2001	        Sun Microsystems, Inc.
118c2ecf20Sopenharmony_ci * Portions Copyright (C) 2003		Red Hat Inc
128c2ecf20Sopenharmony_ci *
138c2ecf20Sopenharmony_ci *
148c2ecf20Sopenharmony_ci * TODO
158c2ecf20Sopenharmony_ci *	Look into engine reset on timeout errors. Should not be required.
168c2ecf20Sopenharmony_ci */
178c2ecf20Sopenharmony_ci
188c2ecf20Sopenharmony_ci#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
198c2ecf20Sopenharmony_ci
208c2ecf20Sopenharmony_ci#include <linux/kernel.h>
218c2ecf20Sopenharmony_ci#include <linux/module.h>
228c2ecf20Sopenharmony_ci#include <linux/pci.h>
238c2ecf20Sopenharmony_ci#include <linux/blkdev.h>
248c2ecf20Sopenharmony_ci#include <linux/delay.h>
258c2ecf20Sopenharmony_ci#include <scsi/scsi_host.h>
268c2ecf20Sopenharmony_ci#include <linux/libata.h>
278c2ecf20Sopenharmony_ci
288c2ecf20Sopenharmony_ci#define DRV_NAME	"pata_hpt366"
298c2ecf20Sopenharmony_ci#define DRV_VERSION	"0.6.11"
308c2ecf20Sopenharmony_ci
318c2ecf20Sopenharmony_cistruct hpt_clock {
328c2ecf20Sopenharmony_ci	u8	xfer_mode;
338c2ecf20Sopenharmony_ci	u32	timing;
348c2ecf20Sopenharmony_ci};
358c2ecf20Sopenharmony_ci
368c2ecf20Sopenharmony_ci/* key for bus clock timings
378c2ecf20Sopenharmony_ci * bit
388c2ecf20Sopenharmony_ci * 0:3    data_high_time. Inactive time of DIOW_/DIOR_ for PIO and MW DMA.
398c2ecf20Sopenharmony_ci *        cycles = value + 1
408c2ecf20Sopenharmony_ci * 4:7    data_low_time. Active time of DIOW_/DIOR_ for PIO and MW DMA.
418c2ecf20Sopenharmony_ci *        cycles = value + 1
428c2ecf20Sopenharmony_ci * 8:11   cmd_high_time. Inactive time of DIOW_/DIOR_ during task file
438c2ecf20Sopenharmony_ci *        register access.
448c2ecf20Sopenharmony_ci * 12:15  cmd_low_time. Active time of DIOW_/DIOR_ during task file
458c2ecf20Sopenharmony_ci *        register access.
468c2ecf20Sopenharmony_ci * 16:18  udma_cycle_time. Clock cycles for UDMA xfer?
478c2ecf20Sopenharmony_ci * 19:21  pre_high_time. Time to initialize 1st cycle for PIO and MW DMA xfer.
488c2ecf20Sopenharmony_ci * 22:24  cmd_pre_high_time. Time to initialize 1st PIO cycle for task file
498c2ecf20Sopenharmony_ci *        register access.
508c2ecf20Sopenharmony_ci * 28     UDMA enable.
518c2ecf20Sopenharmony_ci * 29     DMA  enable.
528c2ecf20Sopenharmony_ci * 30     PIO_MST enable. If set, the chip is in bus master mode during
538c2ecf20Sopenharmony_ci *        PIO xfer.
548c2ecf20Sopenharmony_ci * 31     FIFO enable.
558c2ecf20Sopenharmony_ci */
568c2ecf20Sopenharmony_ci
578c2ecf20Sopenharmony_cistatic const struct hpt_clock hpt366_40[] = {
588c2ecf20Sopenharmony_ci	{	XFER_UDMA_4,	0x900fd943	},
598c2ecf20Sopenharmony_ci	{	XFER_UDMA_3,	0x900ad943	},
608c2ecf20Sopenharmony_ci	{	XFER_UDMA_2,	0x900bd943	},
618c2ecf20Sopenharmony_ci	{	XFER_UDMA_1,	0x9008d943	},
628c2ecf20Sopenharmony_ci	{	XFER_UDMA_0,	0x9008d943	},
638c2ecf20Sopenharmony_ci
648c2ecf20Sopenharmony_ci	{	XFER_MW_DMA_2,	0xa008d943	},
658c2ecf20Sopenharmony_ci	{	XFER_MW_DMA_1,	0xa010d955	},
668c2ecf20Sopenharmony_ci	{	XFER_MW_DMA_0,	0xa010d9fc	},
678c2ecf20Sopenharmony_ci
688c2ecf20Sopenharmony_ci	{	XFER_PIO_4,	0xc008d963	},
698c2ecf20Sopenharmony_ci	{	XFER_PIO_3,	0xc010d974	},
708c2ecf20Sopenharmony_ci	{	XFER_PIO_2,	0xc010d997	},
718c2ecf20Sopenharmony_ci	{	XFER_PIO_1,	0xc010d9c7	},
728c2ecf20Sopenharmony_ci	{	XFER_PIO_0,	0xc018d9d9	},
738c2ecf20Sopenharmony_ci	{	0,		0x0120d9d9	}
748c2ecf20Sopenharmony_ci};
758c2ecf20Sopenharmony_ci
768c2ecf20Sopenharmony_cistatic const struct hpt_clock hpt366_33[] = {
778c2ecf20Sopenharmony_ci	{	XFER_UDMA_4,	0x90c9a731	},
788c2ecf20Sopenharmony_ci	{	XFER_UDMA_3,	0x90cfa731	},
798c2ecf20Sopenharmony_ci	{	XFER_UDMA_2,	0x90caa731	},
808c2ecf20Sopenharmony_ci	{	XFER_UDMA_1,	0x90cba731	},
818c2ecf20Sopenharmony_ci	{	XFER_UDMA_0,	0x90c8a731	},
828c2ecf20Sopenharmony_ci
838c2ecf20Sopenharmony_ci	{	XFER_MW_DMA_2,	0xa0c8a731	},
848c2ecf20Sopenharmony_ci	{	XFER_MW_DMA_1,	0xa0c8a732	},	/* 0xa0c8a733 */
858c2ecf20Sopenharmony_ci	{	XFER_MW_DMA_0,	0xa0c8a797	},
868c2ecf20Sopenharmony_ci
878c2ecf20Sopenharmony_ci	{	XFER_PIO_4,	0xc0c8a731	},
888c2ecf20Sopenharmony_ci	{	XFER_PIO_3,	0xc0c8a742	},
898c2ecf20Sopenharmony_ci	{	XFER_PIO_2,	0xc0d0a753	},
908c2ecf20Sopenharmony_ci	{	XFER_PIO_1,	0xc0d0a7a3	},	/* 0xc0d0a793 */
918c2ecf20Sopenharmony_ci	{	XFER_PIO_0,	0xc0d0a7aa	},	/* 0xc0d0a7a7 */
928c2ecf20Sopenharmony_ci	{	0,		0x0120a7a7	}
938c2ecf20Sopenharmony_ci};
948c2ecf20Sopenharmony_ci
958c2ecf20Sopenharmony_cistatic const struct hpt_clock hpt366_25[] = {
968c2ecf20Sopenharmony_ci	{	XFER_UDMA_4,	0x90c98521	},
978c2ecf20Sopenharmony_ci	{	XFER_UDMA_3,	0x90cf8521	},
988c2ecf20Sopenharmony_ci	{	XFER_UDMA_2,	0x90cf8521	},
998c2ecf20Sopenharmony_ci	{	XFER_UDMA_1,	0x90cb8521	},
1008c2ecf20Sopenharmony_ci	{	XFER_UDMA_0,	0x90cb8521	},
1018c2ecf20Sopenharmony_ci
1028c2ecf20Sopenharmony_ci	{	XFER_MW_DMA_2,	0xa0ca8521	},
1038c2ecf20Sopenharmony_ci	{	XFER_MW_DMA_1,	0xa0ca8532	},
1048c2ecf20Sopenharmony_ci	{	XFER_MW_DMA_0,	0xa0ca8575	},
1058c2ecf20Sopenharmony_ci
1068c2ecf20Sopenharmony_ci	{	XFER_PIO_4,	0xc0ca8521	},
1078c2ecf20Sopenharmony_ci	{	XFER_PIO_3,	0xc0ca8532	},
1088c2ecf20Sopenharmony_ci	{	XFER_PIO_2,	0xc0ca8542	},
1098c2ecf20Sopenharmony_ci	{	XFER_PIO_1,	0xc0d08572	},
1108c2ecf20Sopenharmony_ci	{	XFER_PIO_0,	0xc0d08585	},
1118c2ecf20Sopenharmony_ci	{	0,		0x01208585	}
1128c2ecf20Sopenharmony_ci};
1138c2ecf20Sopenharmony_ci
1148c2ecf20Sopenharmony_ci/**
1158c2ecf20Sopenharmony_ci *	hpt36x_find_mode	-	find the hpt36x timing
1168c2ecf20Sopenharmony_ci *	@ap: ATA port
1178c2ecf20Sopenharmony_ci *	@speed: transfer mode
1188c2ecf20Sopenharmony_ci *
1198c2ecf20Sopenharmony_ci *	Return the 32bit register programming information for this channel
1208c2ecf20Sopenharmony_ci *	that matches the speed provided.
1218c2ecf20Sopenharmony_ci */
1228c2ecf20Sopenharmony_ci
1238c2ecf20Sopenharmony_cistatic u32 hpt36x_find_mode(struct ata_port *ap, int speed)
1248c2ecf20Sopenharmony_ci{
1258c2ecf20Sopenharmony_ci	struct hpt_clock *clocks = ap->host->private_data;
1268c2ecf20Sopenharmony_ci
1278c2ecf20Sopenharmony_ci	while (clocks->xfer_mode) {
1288c2ecf20Sopenharmony_ci		if (clocks->xfer_mode == speed)
1298c2ecf20Sopenharmony_ci			return clocks->timing;
1308c2ecf20Sopenharmony_ci		clocks++;
1318c2ecf20Sopenharmony_ci	}
1328c2ecf20Sopenharmony_ci	BUG();
1338c2ecf20Sopenharmony_ci	return 0xffffffffU;	/* silence compiler warning */
1348c2ecf20Sopenharmony_ci}
1358c2ecf20Sopenharmony_ci
1368c2ecf20Sopenharmony_cistatic const char * const bad_ata33[] = {
1378c2ecf20Sopenharmony_ci	"Maxtor 92720U8", "Maxtor 92040U6", "Maxtor 91360U4", "Maxtor 91020U3",
1388c2ecf20Sopenharmony_ci	"Maxtor 90845U3", "Maxtor 90650U2",
1398c2ecf20Sopenharmony_ci	"Maxtor 91360D8", "Maxtor 91190D7", "Maxtor 91020D6", "Maxtor 90845D5",
1408c2ecf20Sopenharmony_ci	"Maxtor 90680D4", "Maxtor 90510D3", "Maxtor 90340D2",
1418c2ecf20Sopenharmony_ci	"Maxtor 91152D8", "Maxtor 91008D7", "Maxtor 90845D6", "Maxtor 90840D6",
1428c2ecf20Sopenharmony_ci	"Maxtor 90720D5", "Maxtor 90648D5", "Maxtor 90576D4",
1438c2ecf20Sopenharmony_ci	"Maxtor 90510D4",
1448c2ecf20Sopenharmony_ci	"Maxtor 90432D3", "Maxtor 90288D2", "Maxtor 90256D2",
1458c2ecf20Sopenharmony_ci	"Maxtor 91000D8", "Maxtor 90910D8", "Maxtor 90875D7", "Maxtor 90840D7",
1468c2ecf20Sopenharmony_ci	"Maxtor 90750D6", "Maxtor 90625D5", "Maxtor 90500D4",
1478c2ecf20Sopenharmony_ci	"Maxtor 91728D8", "Maxtor 91512D7", "Maxtor 91303D6", "Maxtor 91080D5",
1488c2ecf20Sopenharmony_ci	"Maxtor 90845D4", "Maxtor 90680D4", "Maxtor 90648D3", "Maxtor 90432D2",
1498c2ecf20Sopenharmony_ci	NULL
1508c2ecf20Sopenharmony_ci};
1518c2ecf20Sopenharmony_ci
1528c2ecf20Sopenharmony_cistatic const char * const bad_ata66_4[] = {
1538c2ecf20Sopenharmony_ci	"IBM-DTLA-307075",
1548c2ecf20Sopenharmony_ci	"IBM-DTLA-307060",
1558c2ecf20Sopenharmony_ci	"IBM-DTLA-307045",
1568c2ecf20Sopenharmony_ci	"IBM-DTLA-307030",
1578c2ecf20Sopenharmony_ci	"IBM-DTLA-307020",
1588c2ecf20Sopenharmony_ci	"IBM-DTLA-307015",
1598c2ecf20Sopenharmony_ci	"IBM-DTLA-305040",
1608c2ecf20Sopenharmony_ci	"IBM-DTLA-305030",
1618c2ecf20Sopenharmony_ci	"IBM-DTLA-305020",
1628c2ecf20Sopenharmony_ci	"IC35L010AVER07-0",
1638c2ecf20Sopenharmony_ci	"IC35L020AVER07-0",
1648c2ecf20Sopenharmony_ci	"IC35L030AVER07-0",
1658c2ecf20Sopenharmony_ci	"IC35L040AVER07-0",
1668c2ecf20Sopenharmony_ci	"IC35L060AVER07-0",
1678c2ecf20Sopenharmony_ci	"WDC AC310200R",
1688c2ecf20Sopenharmony_ci	NULL
1698c2ecf20Sopenharmony_ci};
1708c2ecf20Sopenharmony_ci
1718c2ecf20Sopenharmony_cistatic const char * const bad_ata66_3[] = {
1728c2ecf20Sopenharmony_ci	"WDC AC310200R",
1738c2ecf20Sopenharmony_ci	NULL
1748c2ecf20Sopenharmony_ci};
1758c2ecf20Sopenharmony_ci
1768c2ecf20Sopenharmony_cistatic int hpt_dma_blacklisted(const struct ata_device *dev, char *modestr,
1778c2ecf20Sopenharmony_ci			       const char * const list[])
1788c2ecf20Sopenharmony_ci{
1798c2ecf20Sopenharmony_ci	unsigned char model_num[ATA_ID_PROD_LEN + 1];
1808c2ecf20Sopenharmony_ci	int i;
1818c2ecf20Sopenharmony_ci
1828c2ecf20Sopenharmony_ci	ata_id_c_string(dev->id, model_num, ATA_ID_PROD, sizeof(model_num));
1838c2ecf20Sopenharmony_ci
1848c2ecf20Sopenharmony_ci	i = match_string(list, -1, model_num);
1858c2ecf20Sopenharmony_ci	if (i >= 0) {
1868c2ecf20Sopenharmony_ci		pr_warn("%s is not supported for %s\n", modestr, list[i]);
1878c2ecf20Sopenharmony_ci		return 1;
1888c2ecf20Sopenharmony_ci	}
1898c2ecf20Sopenharmony_ci	return 0;
1908c2ecf20Sopenharmony_ci}
1918c2ecf20Sopenharmony_ci
1928c2ecf20Sopenharmony_ci/**
1938c2ecf20Sopenharmony_ci *	hpt366_filter	-	mode selection filter
1948c2ecf20Sopenharmony_ci *	@adev: ATA device
1958c2ecf20Sopenharmony_ci *
1968c2ecf20Sopenharmony_ci *	Block UDMA on devices that cause trouble with this controller.
1978c2ecf20Sopenharmony_ci */
1988c2ecf20Sopenharmony_ci
1998c2ecf20Sopenharmony_cistatic unsigned long hpt366_filter(struct ata_device *adev, unsigned long mask)
2008c2ecf20Sopenharmony_ci{
2018c2ecf20Sopenharmony_ci	if (adev->class == ATA_DEV_ATA) {
2028c2ecf20Sopenharmony_ci		if (hpt_dma_blacklisted(adev, "UDMA",  bad_ata33))
2038c2ecf20Sopenharmony_ci			mask &= ~ATA_MASK_UDMA;
2048c2ecf20Sopenharmony_ci		if (hpt_dma_blacklisted(adev, "UDMA3", bad_ata66_3))
2058c2ecf20Sopenharmony_ci			mask &= ~(0xF8 << ATA_SHIFT_UDMA);
2068c2ecf20Sopenharmony_ci		if (hpt_dma_blacklisted(adev, "UDMA4", bad_ata66_4))
2078c2ecf20Sopenharmony_ci			mask &= ~(0xF0 << ATA_SHIFT_UDMA);
2088c2ecf20Sopenharmony_ci	} else if (adev->class == ATA_DEV_ATAPI)
2098c2ecf20Sopenharmony_ci		mask &= ~(ATA_MASK_MWDMA | ATA_MASK_UDMA);
2108c2ecf20Sopenharmony_ci
2118c2ecf20Sopenharmony_ci	return mask;
2128c2ecf20Sopenharmony_ci}
2138c2ecf20Sopenharmony_ci
2148c2ecf20Sopenharmony_cistatic int hpt36x_cable_detect(struct ata_port *ap)
2158c2ecf20Sopenharmony_ci{
2168c2ecf20Sopenharmony_ci	struct pci_dev *pdev = to_pci_dev(ap->host->dev);
2178c2ecf20Sopenharmony_ci	u8 ata66;
2188c2ecf20Sopenharmony_ci
2198c2ecf20Sopenharmony_ci	/*
2208c2ecf20Sopenharmony_ci	 * Each channel of pata_hpt366 occupies separate PCI function
2218c2ecf20Sopenharmony_ci	 * as the primary channel and bit1 indicates the cable type.
2228c2ecf20Sopenharmony_ci	 */
2238c2ecf20Sopenharmony_ci	pci_read_config_byte(pdev, 0x5A, &ata66);
2248c2ecf20Sopenharmony_ci	if (ata66 & 2)
2258c2ecf20Sopenharmony_ci		return ATA_CBL_PATA40;
2268c2ecf20Sopenharmony_ci	return ATA_CBL_PATA80;
2278c2ecf20Sopenharmony_ci}
2288c2ecf20Sopenharmony_ci
2298c2ecf20Sopenharmony_cistatic void hpt366_set_mode(struct ata_port *ap, struct ata_device *adev,
2308c2ecf20Sopenharmony_ci			    u8 mode)
2318c2ecf20Sopenharmony_ci{
2328c2ecf20Sopenharmony_ci	struct pci_dev *pdev = to_pci_dev(ap->host->dev);
2338c2ecf20Sopenharmony_ci	u32 addr = 0x40 + 4 * adev->devno;
2348c2ecf20Sopenharmony_ci	u32 mask, reg, t;
2358c2ecf20Sopenharmony_ci
2368c2ecf20Sopenharmony_ci	/* determine timing mask and find matching clock entry */
2378c2ecf20Sopenharmony_ci	if (mode < XFER_MW_DMA_0)
2388c2ecf20Sopenharmony_ci		mask = 0xc1f8ffff;
2398c2ecf20Sopenharmony_ci	else if (mode < XFER_UDMA_0)
2408c2ecf20Sopenharmony_ci		mask = 0x303800ff;
2418c2ecf20Sopenharmony_ci	else
2428c2ecf20Sopenharmony_ci		mask = 0x30070000;
2438c2ecf20Sopenharmony_ci
2448c2ecf20Sopenharmony_ci	t = hpt36x_find_mode(ap, mode);
2458c2ecf20Sopenharmony_ci
2468c2ecf20Sopenharmony_ci	/*
2478c2ecf20Sopenharmony_ci	 * Combine new mode bits with old config bits and disable
2488c2ecf20Sopenharmony_ci	 * on-chip PIO FIFO/buffer (and PIO MST mode as well) to avoid
2498c2ecf20Sopenharmony_ci	 * problems handling I/O errors later.
2508c2ecf20Sopenharmony_ci	 */
2518c2ecf20Sopenharmony_ci	pci_read_config_dword(pdev, addr, &reg);
2528c2ecf20Sopenharmony_ci	reg = ((reg & ~mask) | (t & mask)) & ~0xc0000000;
2538c2ecf20Sopenharmony_ci	pci_write_config_dword(pdev, addr, reg);
2548c2ecf20Sopenharmony_ci}
2558c2ecf20Sopenharmony_ci
2568c2ecf20Sopenharmony_ci/**
2578c2ecf20Sopenharmony_ci *	hpt366_set_piomode		-	PIO setup
2588c2ecf20Sopenharmony_ci *	@ap: ATA interface
2598c2ecf20Sopenharmony_ci *	@adev: device on the interface
2608c2ecf20Sopenharmony_ci *
2618c2ecf20Sopenharmony_ci *	Perform PIO mode setup.
2628c2ecf20Sopenharmony_ci */
2638c2ecf20Sopenharmony_ci
2648c2ecf20Sopenharmony_cistatic void hpt366_set_piomode(struct ata_port *ap, struct ata_device *adev)
2658c2ecf20Sopenharmony_ci{
2668c2ecf20Sopenharmony_ci	hpt366_set_mode(ap, adev, adev->pio_mode);
2678c2ecf20Sopenharmony_ci}
2688c2ecf20Sopenharmony_ci
2698c2ecf20Sopenharmony_ci/**
2708c2ecf20Sopenharmony_ci *	hpt366_set_dmamode		-	DMA timing setup
2718c2ecf20Sopenharmony_ci *	@ap: ATA interface
2728c2ecf20Sopenharmony_ci *	@adev: Device being configured
2738c2ecf20Sopenharmony_ci *
2748c2ecf20Sopenharmony_ci *	Set up the channel for MWDMA or UDMA modes. Much the same as with
2758c2ecf20Sopenharmony_ci *	PIO, load the mode number and then set MWDMA or UDMA flag.
2768c2ecf20Sopenharmony_ci */
2778c2ecf20Sopenharmony_ci
2788c2ecf20Sopenharmony_cistatic void hpt366_set_dmamode(struct ata_port *ap, struct ata_device *adev)
2798c2ecf20Sopenharmony_ci{
2808c2ecf20Sopenharmony_ci	hpt366_set_mode(ap, adev, adev->dma_mode);
2818c2ecf20Sopenharmony_ci}
2828c2ecf20Sopenharmony_ci
2838c2ecf20Sopenharmony_cistatic struct scsi_host_template hpt36x_sht = {
2848c2ecf20Sopenharmony_ci	ATA_BMDMA_SHT(DRV_NAME),
2858c2ecf20Sopenharmony_ci};
2868c2ecf20Sopenharmony_ci
2878c2ecf20Sopenharmony_ci/*
2888c2ecf20Sopenharmony_ci *	Configuration for HPT366/68
2898c2ecf20Sopenharmony_ci */
2908c2ecf20Sopenharmony_ci
2918c2ecf20Sopenharmony_cistatic struct ata_port_operations hpt366_port_ops = {
2928c2ecf20Sopenharmony_ci	.inherits	= &ata_bmdma_port_ops,
2938c2ecf20Sopenharmony_ci	.cable_detect	= hpt36x_cable_detect,
2948c2ecf20Sopenharmony_ci	.mode_filter	= hpt366_filter,
2958c2ecf20Sopenharmony_ci	.set_piomode	= hpt366_set_piomode,
2968c2ecf20Sopenharmony_ci	.set_dmamode	= hpt366_set_dmamode,
2978c2ecf20Sopenharmony_ci};
2988c2ecf20Sopenharmony_ci
2998c2ecf20Sopenharmony_ci/**
3008c2ecf20Sopenharmony_ci *	hpt36x_init_chipset	-	common chip setup
3018c2ecf20Sopenharmony_ci *	@dev: PCI device
3028c2ecf20Sopenharmony_ci *
3038c2ecf20Sopenharmony_ci *	Perform the chip setup work that must be done at both init and
3048c2ecf20Sopenharmony_ci *	resume time
3058c2ecf20Sopenharmony_ci */
3068c2ecf20Sopenharmony_ci
3078c2ecf20Sopenharmony_cistatic void hpt36x_init_chipset(struct pci_dev *dev)
3088c2ecf20Sopenharmony_ci{
3098c2ecf20Sopenharmony_ci	u8 drive_fast;
3108c2ecf20Sopenharmony_ci
3118c2ecf20Sopenharmony_ci	pci_write_config_byte(dev, PCI_CACHE_LINE_SIZE, (L1_CACHE_BYTES / 4));
3128c2ecf20Sopenharmony_ci	pci_write_config_byte(dev, PCI_LATENCY_TIMER, 0x78);
3138c2ecf20Sopenharmony_ci	pci_write_config_byte(dev, PCI_MIN_GNT, 0x08);
3148c2ecf20Sopenharmony_ci	pci_write_config_byte(dev, PCI_MAX_LAT, 0x08);
3158c2ecf20Sopenharmony_ci
3168c2ecf20Sopenharmony_ci	pci_read_config_byte(dev, 0x51, &drive_fast);
3178c2ecf20Sopenharmony_ci	if (drive_fast & 0x80)
3188c2ecf20Sopenharmony_ci		pci_write_config_byte(dev, 0x51, drive_fast & ~0x80);
3198c2ecf20Sopenharmony_ci}
3208c2ecf20Sopenharmony_ci
3218c2ecf20Sopenharmony_ci/**
3228c2ecf20Sopenharmony_ci *	hpt36x_init_one		-	Initialise an HPT366/368
3238c2ecf20Sopenharmony_ci *	@dev: PCI device
3248c2ecf20Sopenharmony_ci *	@id: Entry in match table
3258c2ecf20Sopenharmony_ci *
3268c2ecf20Sopenharmony_ci *	Initialise an HPT36x device. There are some interesting complications
3278c2ecf20Sopenharmony_ci *	here. Firstly the chip may report 366 and be one of several variants.
3288c2ecf20Sopenharmony_ci *	Secondly all the timings depend on the clock for the chip which we must
3298c2ecf20Sopenharmony_ci *	detect and look up
3308c2ecf20Sopenharmony_ci *
3318c2ecf20Sopenharmony_ci *	This is the known chip mappings. It may be missing a couple of later
3328c2ecf20Sopenharmony_ci *	releases.
3338c2ecf20Sopenharmony_ci *
3348c2ecf20Sopenharmony_ci *	Chip version		PCI		Rev	Notes
3358c2ecf20Sopenharmony_ci *	HPT366			4 (HPT366)	0	UDMA66
3368c2ecf20Sopenharmony_ci *	HPT366			4 (HPT366)	1	UDMA66
3378c2ecf20Sopenharmony_ci *	HPT368			4 (HPT366)	2	UDMA66
3388c2ecf20Sopenharmony_ci *	HPT37x/30x		4 (HPT366)	3+	Other driver
3398c2ecf20Sopenharmony_ci *
3408c2ecf20Sopenharmony_ci */
3418c2ecf20Sopenharmony_ci
3428c2ecf20Sopenharmony_cistatic int hpt36x_init_one(struct pci_dev *dev, const struct pci_device_id *id)
3438c2ecf20Sopenharmony_ci{
3448c2ecf20Sopenharmony_ci	static const struct ata_port_info info_hpt366 = {
3458c2ecf20Sopenharmony_ci		.flags = ATA_FLAG_SLAVE_POSS,
3468c2ecf20Sopenharmony_ci		.pio_mask = ATA_PIO4,
3478c2ecf20Sopenharmony_ci		.mwdma_mask = ATA_MWDMA2,
3488c2ecf20Sopenharmony_ci		.udma_mask = ATA_UDMA4,
3498c2ecf20Sopenharmony_ci		.port_ops = &hpt366_port_ops
3508c2ecf20Sopenharmony_ci	};
3518c2ecf20Sopenharmony_ci	const struct ata_port_info *ppi[] = { &info_hpt366, NULL };
3528c2ecf20Sopenharmony_ci
3538c2ecf20Sopenharmony_ci	const void *hpriv = NULL;
3548c2ecf20Sopenharmony_ci	u32 reg1;
3558c2ecf20Sopenharmony_ci	int rc;
3568c2ecf20Sopenharmony_ci
3578c2ecf20Sopenharmony_ci	rc = pcim_enable_device(dev);
3588c2ecf20Sopenharmony_ci	if (rc)
3598c2ecf20Sopenharmony_ci		return rc;
3608c2ecf20Sopenharmony_ci
3618c2ecf20Sopenharmony_ci	/* May be a later chip in disguise. Check */
3628c2ecf20Sopenharmony_ci	/* Newer chips are not in the HPT36x driver. Ignore them */
3638c2ecf20Sopenharmony_ci	if (dev->revision > 2)
3648c2ecf20Sopenharmony_ci		return -ENODEV;
3658c2ecf20Sopenharmony_ci
3668c2ecf20Sopenharmony_ci	hpt36x_init_chipset(dev);
3678c2ecf20Sopenharmony_ci
3688c2ecf20Sopenharmony_ci	pci_read_config_dword(dev, 0x40,  &reg1);
3698c2ecf20Sopenharmony_ci
3708c2ecf20Sopenharmony_ci	/* PCI clocking determines the ATA timing values to use */
3718c2ecf20Sopenharmony_ci	/* info_hpt366 is safe against re-entry so we can scribble on it */
3728c2ecf20Sopenharmony_ci	switch ((reg1 & 0xf00) >> 8) {
3738c2ecf20Sopenharmony_ci	case 9:
3748c2ecf20Sopenharmony_ci		hpriv = &hpt366_40;
3758c2ecf20Sopenharmony_ci		break;
3768c2ecf20Sopenharmony_ci	case 5:
3778c2ecf20Sopenharmony_ci		hpriv = &hpt366_25;
3788c2ecf20Sopenharmony_ci		break;
3798c2ecf20Sopenharmony_ci	default:
3808c2ecf20Sopenharmony_ci		hpriv = &hpt366_33;
3818c2ecf20Sopenharmony_ci		break;
3828c2ecf20Sopenharmony_ci	}
3838c2ecf20Sopenharmony_ci	/* Now kick off ATA set up */
3848c2ecf20Sopenharmony_ci	return ata_pci_bmdma_init_one(dev, ppi, &hpt36x_sht, (void *)hpriv, 0);
3858c2ecf20Sopenharmony_ci}
3868c2ecf20Sopenharmony_ci
3878c2ecf20Sopenharmony_ci#ifdef CONFIG_PM_SLEEP
3888c2ecf20Sopenharmony_cistatic int hpt36x_reinit_one(struct pci_dev *dev)
3898c2ecf20Sopenharmony_ci{
3908c2ecf20Sopenharmony_ci	struct ata_host *host = pci_get_drvdata(dev);
3918c2ecf20Sopenharmony_ci	int rc;
3928c2ecf20Sopenharmony_ci
3938c2ecf20Sopenharmony_ci	rc = ata_pci_device_do_resume(dev);
3948c2ecf20Sopenharmony_ci	if (rc)
3958c2ecf20Sopenharmony_ci		return rc;
3968c2ecf20Sopenharmony_ci	hpt36x_init_chipset(dev);
3978c2ecf20Sopenharmony_ci	ata_host_resume(host);
3988c2ecf20Sopenharmony_ci	return 0;
3998c2ecf20Sopenharmony_ci}
4008c2ecf20Sopenharmony_ci#endif
4018c2ecf20Sopenharmony_ci
4028c2ecf20Sopenharmony_cistatic const struct pci_device_id hpt36x[] = {
4038c2ecf20Sopenharmony_ci	{ PCI_VDEVICE(TTI, PCI_DEVICE_ID_TTI_HPT366), },
4048c2ecf20Sopenharmony_ci	{ },
4058c2ecf20Sopenharmony_ci};
4068c2ecf20Sopenharmony_ci
4078c2ecf20Sopenharmony_cistatic struct pci_driver hpt36x_pci_driver = {
4088c2ecf20Sopenharmony_ci	.name		= DRV_NAME,
4098c2ecf20Sopenharmony_ci	.id_table	= hpt36x,
4108c2ecf20Sopenharmony_ci	.probe		= hpt36x_init_one,
4118c2ecf20Sopenharmony_ci	.remove		= ata_pci_remove_one,
4128c2ecf20Sopenharmony_ci#ifdef CONFIG_PM_SLEEP
4138c2ecf20Sopenharmony_ci	.suspend	= ata_pci_device_suspend,
4148c2ecf20Sopenharmony_ci	.resume		= hpt36x_reinit_one,
4158c2ecf20Sopenharmony_ci#endif
4168c2ecf20Sopenharmony_ci};
4178c2ecf20Sopenharmony_ci
4188c2ecf20Sopenharmony_cimodule_pci_driver(hpt36x_pci_driver);
4198c2ecf20Sopenharmony_ci
4208c2ecf20Sopenharmony_ciMODULE_AUTHOR("Alan Cox");
4218c2ecf20Sopenharmony_ciMODULE_DESCRIPTION("low-level driver for the Highpoint HPT366/368");
4228c2ecf20Sopenharmony_ciMODULE_LICENSE("GPL");
4238c2ecf20Sopenharmony_ciMODULE_DEVICE_TABLE(pci, hpt36x);
4248c2ecf20Sopenharmony_ciMODULE_VERSION(DRV_VERSION);
425