* [GIT PULL] libata fixes for v4.12-rc4
From: Tejun Heo @ 2017-06-05 20:21 UTC (permalink / raw)
To: Linus Torvalds; +Cc: linux-kernel, linux-ide
Hello, Linus.
libata fixes for v4.12-rc4.
* Revert of sata_mv devm_ioremap_resource() conversion. It made init
fail if there are overlapping resources which led to detection
failures on some setups.
* A workaround for an Acer laptop which sometimes reports corrupt port
map.
* Other non-critical fixes.
Thanks.
The following changes since commit a95cfad947d5f40cfbf9ad3019575aac1d8ac7a6:
Merge git://git.kernel.org/pub/scm/linux/kernel/git/davem/net (2017-05-15 15:50:49 -0700)
are available in the git repository at:
git://git.kernel.org/pub/scm/linux/kernel/git/tj/libata.git for-4.12-fixes
for you to fetch changes up to f7cf69ae171592d133c69b9adaa5de7cfb6038ea:
libata: fix error checking in in ata_parse_force_one() (2017-05-31 14:26:26 -0400)
----------------------------------------------------------------
Andrew Lunn (1):
Revert "ata: sata_mv: Convert to devm_ioremap_resource()"
Arvind Yadav (1):
ata: sata_rcar: Handle return value of clk_prepare_enable
Sui Chen (1):
ahci: Acer SA5-271 SSD Not Detected Fix
Tejun Heo (1):
libata: fix error checking in in ata_parse_force_one()
Thomas Petazzoni (1):
ata: libahci: properly propagate return value of platform_get_irq()
drivers/ata/ahci.c | 38 ++++++++++++++++++++++++++++++++++++++
drivers/ata/libahci_platform.c | 5 +++--
drivers/ata/libata-core.c | 2 +-
drivers/ata/sata_mv.c | 13 ++++++++-----
drivers/ata/sata_rcar.c | 15 ++++++++++++---
5 files changed, 62 insertions(+), 11 deletions(-)
--
tejun
^ permalink raw reply
* Re: TCG Opal support for libata
From: Tejun Heo @ 2017-06-05 19:30 UTC (permalink / raw)
To: Christoph Hellwig
Cc: Scott Bauer, Jonathan Derrick, Rafael Antognolli, Robert Elliott,
linux-ide, linux-block, linux-scsi, Sergei Shtylyov
In-Reply-To: <20170604124225.27032-1-hch@lst.de>
On Sun, Jun 04, 2017 at 02:42:19PM +0200, Christoph Hellwig wrote:
> Hi all,
>
> this series adds support for using our new generic TCG OPAL code with
> SATA disks, and as side effect for SCSI disks (although so far it doesn't
> seem like none of those actually exist).
Applied 1-5 to libata/for-4.13. Updated 4 for line continuation style
consistency as pointed out by Sergei.
Thanks.
--
tejun
^ permalink raw reply
* Re: [PATCH 4/6] libata: factor out a ata_identify_page_supported helper
From: Sergei Shtylyov @ 2017-06-05 12:46 UTC (permalink / raw)
To: Christoph Hellwig, Tejun Heo
Cc: Scott Bauer, Jonathan Derrick, Rafael Antognolli, Robert Elliott,
linux-ide, linux-block, linux-scsi
In-Reply-To: <20170604124225.27032-5-hch@lst.de>
Hello!
On 06/04/2017 03:42 PM, Christoph Hellwig wrote:
> Signed-off-by: Christoph Hellwig <hch@lst.de>
> ---
> drivers/ata/libata-core.c | 59 +++++++++++++++++++++++++----------------------
> 1 file changed, 32 insertions(+), 27 deletions(-)
>
> diff --git a/drivers/ata/libata-core.c b/drivers/ata/libata-core.c
> index 445e7050637b..f57131115594 100644
> --- a/drivers/ata/libata-core.c
> +++ b/drivers/ata/libata-core.c
> @@ -2120,6 +2120,37 @@ static bool ata_log_supported(struct ata_device *dev, u8 log)
> return get_unaligned_le16(&ap->sector_buf[log * 2]) ? true : false;
> }
>
> +static bool ata_identify_page_supported(struct ata_device *dev, u8 page)
> +{
> + struct ata_port *ap = dev->link->ap;
> + unsigned int err, i;
> +
> + if (!ata_log_supported(dev, ATA_LOG_IDENTIFY_DEVICE)) {
> + ata_dev_warn(dev, "ATA Identify Device Log not supported\n");
> + return false;
> + }
> +
> + /*
> + * Read IDENTIFY DEVICE data log, page 0, to figure out if the page is
> + * supported.
> + */
> + err = ata_read_log_page(dev, ATA_LOG_IDENTIFY_DEVICE, 0, ap->sector_buf,
> + 1);
> + if (err) {
> + ata_dev_info(dev,
> + "failed to get Device Identify Log Emask 0x%x\n",
> + err);
Your line continuation style is spomewhat inconsistent: 2 tabs above and
tabs/spaces here...
[...]
MBR, Sergei
^ permalink raw reply
* [PATCH 4/6] libata: factor out a ata_identify_page_supported helper
From: Christoph Hellwig @ 2017-06-04 12:42 UTC (permalink / raw)
To: Tejun Heo
Cc: Scott Bauer, Jonathan Derrick, Rafael Antognolli, Robert Elliott,
linux-ide, linux-block, linux-scsi
In-Reply-To: <20170604124225.27032-1-hch@lst.de>
Signed-off-by: Christoph Hellwig <hch@lst.de>
---
drivers/ata/libata-core.c | 59 +++++++++++++++++++++++++----------------------
1 file changed, 32 insertions(+), 27 deletions(-)
diff --git a/drivers/ata/libata-core.c b/drivers/ata/libata-core.c
index 445e7050637b..f57131115594 100644
--- a/drivers/ata/libata-core.c
+++ b/drivers/ata/libata-core.c
@@ -2120,6 +2120,37 @@ static bool ata_log_supported(struct ata_device *dev, u8 log)
return get_unaligned_le16(&ap->sector_buf[log * 2]) ? true : false;
}
+static bool ata_identify_page_supported(struct ata_device *dev, u8 page)
+{
+ struct ata_port *ap = dev->link->ap;
+ unsigned int err, i;
+
+ if (!ata_log_supported(dev, ATA_LOG_IDENTIFY_DEVICE)) {
+ ata_dev_warn(dev, "ATA Identify Device Log not supported\n");
+ return false;
+ }
+
+ /*
+ * Read IDENTIFY DEVICE data log, page 0, to figure out if the page is
+ * supported.
+ */
+ err = ata_read_log_page(dev, ATA_LOG_IDENTIFY_DEVICE, 0, ap->sector_buf,
+ 1);
+ if (err) {
+ ata_dev_info(dev,
+ "failed to get Device Identify Log Emask 0x%x\n",
+ err);
+ return false;
+ }
+
+ for (i = 0; i < ap->sector_buf[8]; i++) {
+ if (ap->sector_buf[9 + i] == page)
+ return true;
+ }
+
+ return false;
+}
+
static int ata_do_link_spd_horkage(struct ata_device *dev)
{
struct ata_link *plink = ata_dev_phys_link(dev);
@@ -2325,8 +2356,6 @@ static void ata_dev_config_zac(struct ata_device *dev)
struct ata_port *ap = dev->link->ap;
unsigned int err_mask;
u8 *identify_buf = ap->sector_buf;
- int i, found = 0;
- u16 log_pages;
dev->zac_zones_optimal_open = U32_MAX;
dev->zac_zones_optimal_nonseq = U32_MAX;
@@ -2346,31 +2375,7 @@ static void ata_dev_config_zac(struct ata_device *dev)
if (!(dev->flags & ATA_DFLAG_ZAC))
return;
- if (!ata_log_supported(dev, ATA_LOG_IDENTIFY_DEVICE)) {
- ata_dev_warn(dev, "ATA Identify Device Log not supported\n");
- return;
- }
-
- /*
- * Read IDENTIFY DEVICE data log, page 0, to figure out
- * if page 9 is supported.
- */
- err_mask = ata_read_log_page(dev, ATA_LOG_IDENTIFY_DEVICE, 0,
- identify_buf, 1);
- if (err_mask) {
- ata_dev_info(dev,
- "failed to get Device Identify Log Emask 0x%x\n",
- err_mask);
- return;
- }
- log_pages = identify_buf[8];
- for (i = 0; i < log_pages; i++) {
- if (identify_buf[9 + i] == ATA_LOG_ZONED_INFORMATION) {
- found++;
- break;
- }
- }
- if (!found) {
+ if (!ata_identify_page_supported(dev, ATA_LOG_ZONED_INFORMATION)) {
ata_dev_warn(dev,
"ATA Zoned Information Log not supported\n");
return;
--
2.11.0
^ permalink raw reply related
* [PATCH 6/6] sd: add support for TCG OPAL self encrypting disks
From: Christoph Hellwig @ 2017-06-04 12:42 UTC (permalink / raw)
To: Tejun Heo
Cc: Scott Bauer, Jonathan Derrick, Rafael Antognolli, Robert Elliott,
linux-ide, linux-block, linux-scsi
In-Reply-To: <20170604124225.27032-1-hch@lst.de>
Just wire up the generic TCG OPAL infrastructure to the SCSI disk driver
and the Security In/Out commands.
Note that I don't know of any actual SCSI disks that do support TCG OPAL,
but this is required to support ATA disks through libata.
Signed-off-by: Christoph Hellwig <hch@lst.de>
---
drivers/scsi/sd.c | 44 ++++++++++++++++++++++++++++++++++++++++++++
drivers/scsi/sd.h | 2 ++
2 files changed, 46 insertions(+)
diff --git a/drivers/scsi/sd.c b/drivers/scsi/sd.c
index b6bb4e0ce0e3..782f909a223c 100644
--- a/drivers/scsi/sd.c
+++ b/drivers/scsi/sd.c
@@ -50,6 +50,7 @@
#include <linux/string_helpers.h>
#include <linux/async.h>
#include <linux/slab.h>
+#include <linux/sed-opal.h>
#include <linux/pm_runtime.h>
#include <linux/pr.h>
#include <linux/t10-pi.h>
@@ -643,6 +644,26 @@ static void scsi_disk_put(struct scsi_disk *sdkp)
mutex_unlock(&sd_ref_mutex);
}
+#ifdef CONFIG_BLK_SED_OPAL
+static int sd_sec_submit(void *data, u16 spsp, u8 secp, void *buffer,
+ size_t len, bool send)
+{
+ struct scsi_device *sdev = data;
+ u8 cdb[12] = { 0, };
+ int ret;
+
+ cdb[0] = send ? SECURITY_PROTOCOL_OUT : SECURITY_PROTOCOL_IN;
+ cdb[1] = secp;
+ put_unaligned_be16(spsp, &cdb[2]);
+ put_unaligned_be32(len, &cdb[6]);
+
+ ret = scsi_execute_req(sdev, cdb,
+ send ? DMA_TO_DEVICE : DMA_FROM_DEVICE,
+ buffer, len, NULL, SD_TIMEOUT, SD_MAX_RETRIES, NULL);
+ return ret <= 0 ? ret : -EIO;
+}
+#endif /* CONFIG_BLK_SED_OPAL */
+
static unsigned char sd_setup_protect_cmnd(struct scsi_cmnd *scmd,
unsigned int dix, unsigned int dif)
{
@@ -1454,6 +1475,9 @@ static int sd_ioctl(struct block_device *bdev, fmode_t mode,
if (error)
goto out;
+ if (is_sed_ioctl(cmd))
+ return sed_ioctl(sdkp->opal_dev, cmd, p);
+
/*
* Send SCSI addressing ioctls directly to mid level, send other
* ioctls to block level and then onto mid level if they can't be
@@ -3014,6 +3038,17 @@ static void sd_read_write_same(struct scsi_disk *sdkp, unsigned char *buffer)
sdkp->ws10 = 1;
}
+static void sd_read_security(struct scsi_disk *sdkp, unsigned char *buffer)
+{
+ struct scsi_device *sdev = sdkp->device;
+
+ if (scsi_report_opcode(sdev, buffer, SD_BUF_SIZE,
+ SECURITY_PROTOCOL_IN) == 1 &&
+ scsi_report_opcode(sdev, buffer, SD_BUF_SIZE,
+ SECURITY_PROTOCOL_OUT) == 1)
+ sdkp->security = 1;
+}
+
/**
* sd_revalidate_disk - called the first time a new disk is seen,
* performs disk spin up, read_capacity, etc.
@@ -3067,6 +3102,7 @@ static int sd_revalidate_disk(struct gendisk *disk)
sd_read_cache_type(sdkp, buffer);
sd_read_app_tag_own(sdkp, buffer);
sd_read_write_same(sdkp, buffer);
+ sd_read_security(sdkp, buffer);
}
sdkp->first_scan = 0;
@@ -3227,6 +3263,12 @@ static void sd_probe_async(void *data, async_cookie_t cookie)
sd_revalidate_disk(gd);
+ if (sdkp->security) {
+ sdkp->opal_dev = init_opal_dev(sdp, &sd_sec_submit);
+ if (sdkp->opal_dev)
+ sd_printk(KERN_NOTICE, sdkp, "supports TCG Opal\n");
+ }
+
sd_printk(KERN_NOTICE, sdkp, "Attached SCSI %sdisk\n",
sdp->removable ? "removable " : "");
scsi_autopm_put_device(sdp);
@@ -3376,6 +3418,8 @@ static int sd_remove(struct device *dev)
sd_zbc_remove(sdkp);
+ free_opal_dev(sdkp->opal_dev);
+
blk_register_region(devt, SD_MINORS, NULL,
sd_default_probe, NULL, NULL);
diff --git a/drivers/scsi/sd.h b/drivers/scsi/sd.h
index 61d02efd366c..99c4dde9b6bf 100644
--- a/drivers/scsi/sd.h
+++ b/drivers/scsi/sd.h
@@ -71,6 +71,7 @@ struct scsi_disk {
struct scsi_device *device;
struct device dev;
struct gendisk *disk;
+ struct opal_dev *opal_dev;
#ifdef CONFIG_BLK_DEV_ZONED
unsigned int nr_zones;
unsigned int zone_blocks;
@@ -114,6 +115,7 @@ struct scsi_disk {
unsigned rc_basis: 2;
unsigned zoned: 2;
unsigned urswrz : 1;
+ unsigned security : 1;
unsigned ignore_medium_access_errors : 1;
};
#define to_scsi_disk(obj) container_of(obj,struct scsi_disk,dev)
--
2.11.0
^ permalink raw reply related
* [PATCH 5/6] libata: implement SECURITY PROTOCOL IN/OUT
From: Christoph Hellwig @ 2017-06-04 12:42 UTC (permalink / raw)
To: Tejun Heo
Cc: Scott Bauer, Jonathan Derrick, Rafael Antognolli, Robert Elliott,
linux-ide, linux-block, linux-scsi
In-Reply-To: <20170604124225.27032-1-hch@lst.de>
This allows us to use the generic OPAL code with ATA devices.
Signed-off-by: Christoph Hellwig <hch@lst.de>
---
drivers/ata/libata-core.c | 32 ++++++++++++++++++++
drivers/ata/libata-scsi.c | 76 +++++++++++++++++++++++++++++++++++++++++++++++
include/linux/ata.h | 1 +
include/linux/libata.h | 1 +
4 files changed, 110 insertions(+)
diff --git a/drivers/ata/libata-core.c b/drivers/ata/libata-core.c
index f57131115594..6eb08595a1b5 100644
--- a/drivers/ata/libata-core.c
+++ b/drivers/ata/libata-core.c
@@ -2405,6 +2405,37 @@ static void ata_dev_config_zac(struct ata_device *dev)
}
}
+static void ata_dev_config_trusted(struct ata_device *dev)
+{
+ struct ata_port *ap = dev->link->ap;
+ u64 trusted_cap;
+ unsigned int err;
+
+ if (!ata_identify_page_supported(dev, ATA_LOG_SECURITY)) {
+ ata_dev_warn(dev,
+ "Security Log not supported\n");
+ return;
+ }
+
+ err = ata_read_log_page(dev, ATA_LOG_IDENTIFY_DEVICE, ATA_LOG_SECURITY,
+ ap->sector_buf, 1);
+ if (err) {
+ ata_dev_dbg(dev,
+ "failed to read Security Log, Emask 0x%x\n", err);
+ return;
+ }
+
+ trusted_cap = get_unaligned_le64(&ap->sector_buf[40]);
+ if (!(trusted_cap & (1ULL << 63))) {
+ ata_dev_dbg(dev,
+ "Trusted Computing capability qword not valid!\n");
+ return;
+ }
+
+ if (trusted_cap & (1 << 0))
+ dev->flags |= ATA_DFLAG_TRUSTED;
+}
+
/**
* ata_dev_configure - Configure the specified ATA/ATAPI device
* @dev: Target device to configure
@@ -2629,6 +2660,7 @@ int ata_dev_configure(struct ata_device *dev)
}
ata_dev_config_sense_reporting(dev);
ata_dev_config_zac(dev);
+ ata_dev_config_trusted(dev);
dev->cdb_len = 16;
}
diff --git a/drivers/ata/libata-scsi.c b/drivers/ata/libata-scsi.c
index 49ba9834c715..3d28f2bd79af 100644
--- a/drivers/ata/libata-scsi.c
+++ b/drivers/ata/libata-scsi.c
@@ -3563,6 +3563,11 @@ static unsigned int ata_scsiop_maint_in(struct ata_scsi_args *args, u8 *rbuf)
dev->class == ATA_DEV_ZAC)
supported = 3;
break;
+ case SECURITY_PROTOCOL_IN:
+ case SECURITY_PROTOCOL_OUT:
+ if (dev->flags & ATA_DFLAG_TRUSTED)
+ supported = 3;
+ break;
default:
break;
}
@@ -4067,6 +4072,71 @@ static unsigned int ata_scsi_mode_select_xlat(struct ata_queued_cmd *qc)
return 1;
}
+static u8 ata_scsi_trusted_op(u32 len, bool send, bool dma)
+{
+ if (len == 0)
+ return ATA_CMD_TRUSTED_NONDATA;
+ else if (send)
+ return dma ? ATA_CMD_TRUSTED_SND_DMA : ATA_CMD_TRUSTED_SND;
+ else
+ return dma ? ATA_CMD_TRUSTED_RCV_DMA : ATA_CMD_TRUSTED_RCV;
+}
+
+static unsigned int ata_scsi_security_inout_xlat(struct ata_queued_cmd *qc)
+{
+ struct scsi_cmnd *scmd = qc->scsicmd;
+ const u8 *cdb = scmd->cmnd;
+ struct ata_taskfile *tf = &qc->tf;
+ u8 secp = cdb[1];
+ bool send = (cdb[0] == SECURITY_PROTOCOL_OUT);
+ u16 spsp = get_unaligned_be16(&cdb[2]);
+ u32 len = get_unaligned_be32(&cdb[6]);
+ bool dma = !(qc->dev->flags & ATA_DFLAG_PIO);
+
+ /*
+ * We don't support the ATA "security" protocol.
+ */
+ if (secp == 0xef) {
+ ata_scsi_set_invalid_field(qc->dev, scmd, 1, 0);
+ return 1;
+ }
+
+ if (cdb[4] & 7) { /* INC_512 */
+ if (len > 0xffff) {
+ ata_scsi_set_invalid_field(qc->dev, scmd, 6, 0);
+ return 1;
+ }
+ } else {
+ if (len > 0x01fffe00) {
+ ata_scsi_set_invalid_field(qc->dev, scmd, 6, 0);
+ return 1;
+ }
+
+ /* convert to the sector-based ATA addressing */
+ len = (len + 511) / 512;
+ }
+
+ tf->protocol = dma ? ATA_PROT_DMA : ATA_PROT_PIO;
+ tf->flags |= ATA_TFLAG_DEVICE | ATA_TFLAG_ISADDR | ATA_TFLAG_LBA;
+ if (send)
+ tf->flags |= ATA_TFLAG_WRITE;
+ tf->command = ata_scsi_trusted_op(len, send, dma);
+ tf->feature = secp;
+ tf->lbam = spsp & 0xff;
+ tf->lbah = spsp >> 8;
+
+ if (len) {
+ tf->nsect = len & 0xff;
+ tf->lbal = len >> 8;
+ } else {
+ if (!send)
+ tf->lbah = (1 << 7);
+ }
+
+ ata_qc_set_pc_nbytes(qc);
+ return 0;
+}
+
/**
* ata_get_xlat_func - check if SCSI to ATA translation is possible
* @dev: ATA device
@@ -4118,6 +4188,12 @@ static inline ata_xlat_func_t ata_get_xlat_func(struct ata_device *dev, u8 cmd)
case ZBC_OUT:
return ata_scsi_zbc_out_xlat;
+ case SECURITY_PROTOCOL_IN:
+ case SECURITY_PROTOCOL_OUT:
+ if (!(dev->flags & ATA_DFLAG_TRUSTED))
+ break;
+ return ata_scsi_security_inout_xlat;
+
case START_STOP:
return ata_scsi_start_stop_xlat;
}
diff --git a/include/linux/ata.h b/include/linux/ata.h
index 44de34c954d8..5781bf310560 100644
--- a/include/linux/ata.h
+++ b/include/linux/ata.h
@@ -341,6 +341,7 @@ enum {
ATA_LOG_IDENTIFY_DEVICE = 0x30,
/* Identify device log pages: */
+ ATA_LOG_SECURITY = 0x06,
ATA_LOG_SATA_SETTINGS = 0x08,
ATA_LOG_ZONED_INFORMATION = 0x09,
diff --git a/include/linux/libata.h b/include/linux/libata.h
index c9a69fc8821e..65711cb3a740 100644
--- a/include/linux/libata.h
+++ b/include/linux/libata.h
@@ -156,6 +156,7 @@ enum {
ATA_DFLAG_ACPI_PENDING = (1 << 5), /* ACPI resume action pending */
ATA_DFLAG_ACPI_FAILED = (1 << 6), /* ACPI on devcfg has failed */
ATA_DFLAG_AN = (1 << 7), /* AN configured */
+ ATA_DFLAG_TRUSTED = (1 << 8), /* device supports trusted send/recv */
ATA_DFLAG_DMADIR = (1 << 10), /* device requires DMADIR */
ATA_DFLAG_CFG_MASK = (1 << 12) - 1,
--
2.11.0
^ permalink raw reply related
* [PATCH 3/6] libata: clarify log page naming / grouping
From: Christoph Hellwig @ 2017-06-04 12:42 UTC (permalink / raw)
To: Tejun Heo
Cc: Scott Bauer, Jonathan Derrick, Rafael Antognolli, Robert Elliott,
linux-ide, linux-block, linux-scsi
In-Reply-To: <20170604124225.27032-1-hch@lst.de>
Signed-off-by: Christoph Hellwig <hch@lst.de>
---
drivers/ata/libata-core.c | 10 +++++-----
include/linux/ata.h | 10 +++++++---
2 files changed, 12 insertions(+), 8 deletions(-)
diff --git a/drivers/ata/libata-core.c b/drivers/ata/libata-core.c
index 0672733997bb..445e7050637b 100644
--- a/drivers/ata/libata-core.c
+++ b/drivers/ata/libata-core.c
@@ -2226,7 +2226,7 @@ static void ata_dev_config_ncq_prio(struct ata_device *dev)
}
err_mask = ata_read_log_page(dev,
- ATA_LOG_SATA_ID_DEV_DATA,
+ ATA_LOG_IDENTIFY_DEVICE,
ATA_LOG_SATA_SETTINGS,
ap->sector_buf,
1);
@@ -2346,7 +2346,7 @@ static void ata_dev_config_zac(struct ata_device *dev)
if (!(dev->flags & ATA_DFLAG_ZAC))
return;
- if (!ata_log_supported(dev, ATA_LOG_SATA_ID_DEV_DATA)) {
+ if (!ata_log_supported(dev, ATA_LOG_IDENTIFY_DEVICE)) {
ata_dev_warn(dev, "ATA Identify Device Log not supported\n");
return;
}
@@ -2355,7 +2355,7 @@ static void ata_dev_config_zac(struct ata_device *dev)
* Read IDENTIFY DEVICE data log, page 0, to figure out
* if page 9 is supported.
*/
- err_mask = ata_read_log_page(dev, ATA_LOG_SATA_ID_DEV_DATA, 0,
+ err_mask = ata_read_log_page(dev, ATA_LOG_IDENTIFY_DEVICE, 0,
identify_buf, 1);
if (err_mask) {
ata_dev_info(dev,
@@ -2379,7 +2379,7 @@ static void ata_dev_config_zac(struct ata_device *dev)
/*
* Read IDENTIFY DEVICE data log, page 9 (Zoned-device information)
*/
- err_mask = ata_read_log_page(dev, ATA_LOG_SATA_ID_DEV_DATA,
+ err_mask = ata_read_log_page(dev, ATA_LOG_IDENTIFY_DEVICE,
ATA_LOG_ZONED_INFORMATION,
identify_buf, 1);
if (!err_mask) {
@@ -2608,7 +2608,7 @@ int ata_dev_configure(struct ata_device *dev)
dev->flags |= ATA_DFLAG_DEVSLP;
err_mask = ata_read_log_page(dev,
- ATA_LOG_SATA_ID_DEV_DATA,
+ ATA_LOG_IDENTIFY_DEVICE,
ATA_LOG_SATA_SETTINGS,
sata_setting,
1);
diff --git a/include/linux/ata.h b/include/linux/ata.h
index ad7d9ee89ff0..44de34c954d8 100644
--- a/include/linux/ata.h
+++ b/include/linux/ata.h
@@ -336,11 +336,15 @@ enum {
/* READ_LOG_EXT pages */
ATA_LOG_DIRECTORY = 0x0,
ATA_LOG_SATA_NCQ = 0x10,
- ATA_LOG_NCQ_NON_DATA = 0x12,
- ATA_LOG_NCQ_SEND_RECV = 0x13,
- ATA_LOG_SATA_ID_DEV_DATA = 0x30,
+ ATA_LOG_NCQ_NON_DATA = 0x12,
+ ATA_LOG_NCQ_SEND_RECV = 0x13,
+ ATA_LOG_IDENTIFY_DEVICE = 0x30,
+
+ /* Identify device log pages: */
ATA_LOG_SATA_SETTINGS = 0x08,
ATA_LOG_ZONED_INFORMATION = 0x09,
+
+ /* Identify device SATA settings log:*/
ATA_LOG_DEVSLP_OFFSET = 0x30,
ATA_LOG_DEVSLP_SIZE = 0x08,
ATA_LOG_DEVSLP_MDAT = 0x00,
--
2.11.0
^ permalink raw reply related
* [PATCH 2/6] libata: factor out a ata_log_supported helper
From: Christoph Hellwig @ 2017-06-04 12:42 UTC (permalink / raw)
To: Tejun Heo
Cc: Scott Bauer, Jonathan Derrick, Rafael Antognolli, Robert Elliott,
linux-ide, linux-block, linux-scsi
In-Reply-To: <20170604124225.27032-1-hch@lst.de>
Signed-off-by: Christoph Hellwig <hch@lst.de>
---
drivers/ata/libata-core.c | 59 +++++++++++++----------------------------------
1 file changed, 16 insertions(+), 43 deletions(-)
diff --git a/drivers/ata/libata-core.c b/drivers/ata/libata-core.c
index d4bab5052268..0672733997bb 100644
--- a/drivers/ata/libata-core.c
+++ b/drivers/ata/libata-core.c
@@ -2111,6 +2111,15 @@ unsigned int ata_read_log_page(struct ata_device *dev, u8 log,
return err_mask;
}
+static bool ata_log_supported(struct ata_device *dev, u8 log)
+{
+ struct ata_port *ap = dev->link->ap;
+
+ if (ata_read_log_page(dev, ATA_LOG_DIRECTORY, 0, ap->sector_buf, 1))
+ return false;
+ return get_unaligned_le16(&ap->sector_buf[log * 2]) ? true : false;
+}
+
static int ata_do_link_spd_horkage(struct ata_device *dev)
{
struct ata_link *plink = ata_dev_phys_link(dev);
@@ -2158,21 +2167,9 @@ static void ata_dev_config_ncq_send_recv(struct ata_device *dev)
{
struct ata_port *ap = dev->link->ap;
unsigned int err_mask;
- int log_index = ATA_LOG_NCQ_SEND_RECV * 2;
- u16 log_pages;
- err_mask = ata_read_log_page(dev, ATA_LOG_DIRECTORY,
- 0, ap->sector_buf, 1);
- if (err_mask) {
- ata_dev_dbg(dev,
- "failed to get Log Directory Emask 0x%x\n",
- err_mask);
- return;
- }
- log_pages = get_unaligned_le16(&ap->sector_buf[log_index]);
- if (!log_pages) {
- ata_dev_warn(dev,
- "NCQ Send/Recv Log not supported\n");
+ if (!ata_log_supported(dev, ATA_LOG_NCQ_SEND_RECV)) {
+ ata_dev_warn(dev, "NCQ Send/Recv Log not supported\n");
return;
}
err_mask = ata_read_log_page(dev, ATA_LOG_NCQ_SEND_RECV,
@@ -2199,19 +2196,8 @@ static void ata_dev_config_ncq_non_data(struct ata_device *dev)
{
struct ata_port *ap = dev->link->ap;
unsigned int err_mask;
- int log_index = ATA_LOG_NCQ_NON_DATA * 2;
- u16 log_pages;
- err_mask = ata_read_log_page(dev, ATA_LOG_DIRECTORY,
- 0, ap->sector_buf, 1);
- if (err_mask) {
- ata_dev_dbg(dev,
- "failed to get Log Directory Emask 0x%x\n",
- err_mask);
- return;
- }
- log_pages = get_unaligned_le16(&ap->sector_buf[log_index]);
- if (!log_pages) {
+ if (!ata_log_supported(dev, ATA_LOG_NCQ_NON_DATA)) {
ata_dev_warn(dev,
"NCQ Send/Recv Log not supported\n");
return;
@@ -2339,7 +2325,7 @@ static void ata_dev_config_zac(struct ata_device *dev)
struct ata_port *ap = dev->link->ap;
unsigned int err_mask;
u8 *identify_buf = ap->sector_buf;
- int log_index = ATA_LOG_SATA_ID_DEV_DATA * 2, i, found = 0;
+ int i, found = 0;
u16 log_pages;
dev->zac_zones_optimal_open = U32_MAX;
@@ -2360,24 +2346,11 @@ static void ata_dev_config_zac(struct ata_device *dev)
if (!(dev->flags & ATA_DFLAG_ZAC))
return;
- /*
- * Read Log Directory to figure out if IDENTIFY DEVICE log
- * is supported.
- */
- err_mask = ata_read_log_page(dev, ATA_LOG_DIRECTORY,
- 0, ap->sector_buf, 1);
- if (err_mask) {
- ata_dev_info(dev,
- "failed to get Log Directory Emask 0x%x\n",
- err_mask);
- return;
- }
- log_pages = get_unaligned_le16(&ap->sector_buf[log_index]);
- if (log_pages == 0) {
- ata_dev_warn(dev,
- "ATA Identify Device Log not supported\n");
+ if (!ata_log_supported(dev, ATA_LOG_SATA_ID_DEV_DATA)) {
+ ata_dev_warn(dev, "ATA Identify Device Log not supported\n");
return;
}
+
/*
* Read IDENTIFY DEVICE data log, page 0, to figure out
* if page 9 is supported.
--
2.11.0
^ permalink raw reply related
* [PATCH 1/6] libata: move ata_read_log_page to libata-core.c
From: Christoph Hellwig @ 2017-06-04 12:42 UTC (permalink / raw)
To: Tejun Heo
Cc: Scott Bauer, Jonathan Derrick, Rafael Antognolli, Robert Elliott,
linux-ide, linux-block, linux-scsi
In-Reply-To: <20170604124225.27032-1-hch@lst.de>
It is core functionality, and only one of the users is in the EH code.
Signed-off-by: Christoph Hellwig <hch@lst.de>
---
drivers/ata/libata-core.c | 64 +++++++++++++++++++++++++++++++++++++++++++++++
drivers/ata/libata-eh.c | 64 -----------------------------------------------
drivers/ata/libata.h | 4 +--
3 files changed, 66 insertions(+), 66 deletions(-)
diff --git a/drivers/ata/libata-core.c b/drivers/ata/libata-core.c
index 2d83b8c75965..d4bab5052268 100644
--- a/drivers/ata/libata-core.c
+++ b/drivers/ata/libata-core.c
@@ -2047,6 +2047,70 @@ int ata_dev_read_id(struct ata_device *dev, unsigned int *p_class,
return rc;
}
+/**
+ * ata_read_log_page - read a specific log page
+ * @dev: target device
+ * @log: log to read
+ * @page: page to read
+ * @buf: buffer to store read page
+ * @sectors: number of sectors to read
+ *
+ * Read log page using READ_LOG_EXT command.
+ *
+ * LOCKING:
+ * Kernel thread context (may sleep).
+ *
+ * RETURNS:
+ * 0 on success, AC_ERR_* mask otherwise.
+ */
+unsigned int ata_read_log_page(struct ata_device *dev, u8 log,
+ u8 page, void *buf, unsigned int sectors)
+{
+ unsigned long ap_flags = dev->link->ap->flags;
+ struct ata_taskfile tf;
+ unsigned int err_mask;
+ bool dma = false;
+
+ DPRINTK("read log page - log 0x%x, page 0x%x\n", log, page);
+
+ /*
+ * Return error without actually issuing the command on controllers
+ * which e.g. lockup on a read log page.
+ */
+ if (ap_flags & ATA_FLAG_NO_LOG_PAGE)
+ return AC_ERR_DEV;
+
+retry:
+ ata_tf_init(dev, &tf);
+ if (dev->dma_mode && ata_id_has_read_log_dma_ext(dev->id) &&
+ !(dev->horkage & ATA_HORKAGE_NO_NCQ_LOG)) {
+ tf.command = ATA_CMD_READ_LOG_DMA_EXT;
+ tf.protocol = ATA_PROT_DMA;
+ dma = true;
+ } else {
+ tf.command = ATA_CMD_READ_LOG_EXT;
+ tf.protocol = ATA_PROT_PIO;
+ dma = false;
+ }
+ tf.lbal = log;
+ tf.lbam = page;
+ tf.nsect = sectors;
+ tf.hob_nsect = sectors >> 8;
+ tf.flags |= ATA_TFLAG_ISADDR | ATA_TFLAG_LBA48 | ATA_TFLAG_DEVICE;
+
+ err_mask = ata_exec_internal(dev, &tf, NULL, DMA_FROM_DEVICE,
+ buf, sectors * ATA_SECT_SIZE, 0);
+
+ if (err_mask && dma) {
+ dev->horkage |= ATA_HORKAGE_NO_NCQ_LOG;
+ ata_dev_warn(dev, "READ LOG DMA EXT failed, trying unqueued\n");
+ goto retry;
+ }
+
+ DPRINTK("EXIT, err_mask=%x\n", err_mask);
+ return err_mask;
+}
+
static int ata_do_link_spd_horkage(struct ata_device *dev)
{
struct ata_link *plink = ata_dev_phys_link(dev);
diff --git a/drivers/ata/libata-eh.c b/drivers/ata/libata-eh.c
index ef68232b5222..528a4e1b2af3 100644
--- a/drivers/ata/libata-eh.c
+++ b/drivers/ata/libata-eh.c
@@ -1488,70 +1488,6 @@ static const char *ata_err_string(unsigned int err_mask)
}
/**
- * ata_read_log_page - read a specific log page
- * @dev: target device
- * @log: log to read
- * @page: page to read
- * @buf: buffer to store read page
- * @sectors: number of sectors to read
- *
- * Read log page using READ_LOG_EXT command.
- *
- * LOCKING:
- * Kernel thread context (may sleep).
- *
- * RETURNS:
- * 0 on success, AC_ERR_* mask otherwise.
- */
-unsigned int ata_read_log_page(struct ata_device *dev, u8 log,
- u8 page, void *buf, unsigned int sectors)
-{
- unsigned long ap_flags = dev->link->ap->flags;
- struct ata_taskfile tf;
- unsigned int err_mask;
- bool dma = false;
-
- DPRINTK("read log page - log 0x%x, page 0x%x\n", log, page);
-
- /*
- * Return error without actually issuing the command on controllers
- * which e.g. lockup on a read log page.
- */
- if (ap_flags & ATA_FLAG_NO_LOG_PAGE)
- return AC_ERR_DEV;
-
-retry:
- ata_tf_init(dev, &tf);
- if (dev->dma_mode && ata_id_has_read_log_dma_ext(dev->id) &&
- !(dev->horkage & ATA_HORKAGE_NO_NCQ_LOG)) {
- tf.command = ATA_CMD_READ_LOG_DMA_EXT;
- tf.protocol = ATA_PROT_DMA;
- dma = true;
- } else {
- tf.command = ATA_CMD_READ_LOG_EXT;
- tf.protocol = ATA_PROT_PIO;
- dma = false;
- }
- tf.lbal = log;
- tf.lbam = page;
- tf.nsect = sectors;
- tf.hob_nsect = sectors >> 8;
- tf.flags |= ATA_TFLAG_ISADDR | ATA_TFLAG_LBA48 | ATA_TFLAG_DEVICE;
-
- err_mask = ata_exec_internal(dev, &tf, NULL, DMA_FROM_DEVICE,
- buf, sectors * ATA_SECT_SIZE, 0);
-
- if (err_mask && dma) {
- dev->horkage |= ATA_HORKAGE_NO_NCQ_LOG;
- ata_dev_warn(dev, "READ LOG DMA EXT failed, trying unqueued\n");
- goto retry;
- }
-
- DPRINTK("EXIT, err_mask=%x\n", err_mask);
- return err_mask;
-}
-
-/**
* ata_eh_read_log_10h - Read log page 10h for NCQ error details
* @dev: Device to read log page 10h from
* @tag: Resulting tag of the failed command
diff --git a/drivers/ata/libata.h b/drivers/ata/libata.h
index 120fce0befd3..84569d563ae2 100644
--- a/drivers/ata/libata.h
+++ b/drivers/ata/libata.h
@@ -98,6 +98,8 @@ extern struct ata_port *ata_port_alloc(struct ata_host *host);
extern const char *sata_spd_string(unsigned int spd);
extern int ata_port_probe(struct ata_port *ap);
extern void __ata_port_probe(struct ata_port *ap);
+extern unsigned int ata_read_log_page(struct ata_device *dev, u8 log,
+ u8 page, void *buf, unsigned int sectors);
#define to_ata_port(d) container_of(d, struct ata_port, tdev)
@@ -160,8 +162,6 @@ extern void ata_eh_about_to_do(struct ata_link *link, struct ata_device *dev,
unsigned int action);
extern void ata_eh_done(struct ata_link *link, struct ata_device *dev,
unsigned int action);
-extern unsigned int ata_read_log_page(struct ata_device *dev, u8 log,
- u8 page, void *buf, unsigned int sectors);
extern void ata_eh_autopsy(struct ata_port *ap);
const char *ata_get_cmd_descript(u8 command);
extern void ata_eh_report(struct ata_port *ap);
--
2.11.0
^ permalink raw reply related
* TCG Opal support for libata
From: Christoph Hellwig @ 2017-06-04 12:42 UTC (permalink / raw)
To: Tejun Heo
Cc: Scott Bauer, Jonathan Derrick, Rafael Antognolli, Robert Elliott,
linux-ide, linux-block, linux-scsi
Hi all,
this series adds support for using our new generic TCG OPAL code with
SATA disks, and as side effect for SCSI disks (although so far it doesn't
seem like none of those actually exist).
^ permalink raw reply
* [PATCH 4/4 v4] ARM: dts: add Gemini PATA/SATA support
From: Linus Walleij @ 2017-06-04 8:50 UTC (permalink / raw)
To: Tejun Heo, Bartlomiej Zolnierkiewicz, linux-ide
Cc: Janos Laube, Paulius Zaleckas, linux-arm-kernel, Hans Ulli Kroll,
Florian Fainelli, Linus Walleij, John Feng-Hsin Chiang,
Greentime Hu
In-Reply-To: <20170604085009.11902-1-linus.walleij@linaro.org>
The NAS4229B and SQ201 Gemini systems have a PATA controller
which is linked to a SATA bridge in the SoC. Enable both
platforms to use the PATA/SATA devices.
Cc: John Feng-Hsin Chiang <john453@faraday-tech.com>
Cc: Greentime Hu <green.hu@gmail.com>
Acked-by: Hans Ulli Kroll <ulli.kroll@googlemail.com>
Signed-off-by: Linus Walleij <linus.walleij@linaro.org>
---
ChangeLog v3->v4:
- No changes, just resending to keep the patch set together.
ChangeLog v2->v3:
- No changes, just resending to keep the patch set together.
- Cut the timings also from the second device instance.
ChangeLog v1->v2:
- Cut the timings - we open code these in the driver instead.
- Reference syscon node for clocks and resets as requested by
the devicetree reviewers.
- Use reset line #defines from the new header file.
PATA maintainers: this file will be applied by me through the ARM
SoC git tree. It is provided for reference only so you see how
it will be used.
---
arch/arm/boot/dts/gemini-nas4220b.dts | 10 ++++++++++
arch/arm/boot/dts/gemini-sq201.dts | 10 ++++++++++
arch/arm/boot/dts/gemini.dtsi | 35 +++++++++++++++++++++++++++++++++++
3 files changed, 55 insertions(+)
diff --git a/arch/arm/boot/dts/gemini-nas4220b.dts b/arch/arm/boot/dts/gemini-nas4220b.dts
index 7668ba52158e..55f6a4f1f801 100644
--- a/arch/arm/boot/dts/gemini-nas4220b.dts
+++ b/arch/arm/boot/dts/gemini-nas4220b.dts
@@ -98,5 +98,15 @@
read-only;
};
};
+
+ sata: sata@46000000 {
+ cortina,gemini-ata-muxmode = <0>;
+ cortina,gemini-enable-sata-bridge;
+ status = "okay";
+ };
+
+ ata@63000000 {
+ status = "okay";
+ };
};
};
diff --git a/arch/arm/boot/dts/gemini-sq201.dts b/arch/arm/boot/dts/gemini-sq201.dts
index 46309e79cc7b..4d200f0bcd45 100644
--- a/arch/arm/boot/dts/gemini-sq201.dts
+++ b/arch/arm/boot/dts/gemini-sq201.dts
@@ -93,6 +93,12 @@
};
};
+ sata: sata@46000000 {
+ cortina,gemini-ata-muxmode = <0>;
+ cortina,gemini-enable-sata-bridge;
+ status = "okay";
+ };
+
pci@50000000 {
status = "okay";
interrupt-map-mask = <0xf800 0 0 7>;
@@ -114,5 +120,9 @@
<0x6000 0 0 3 &pci_intc 1>,
<0x6000 0 0 4 &pci_intc 2>;
};
+
+ ata@63000000 {
+ status = "okay";
+ };
};
};
diff --git a/arch/arm/boot/dts/gemini.dtsi b/arch/arm/boot/dts/gemini.dtsi
index 8e833744e855..49cce9e9d51f 100644
--- a/arch/arm/boot/dts/gemini.dtsi
+++ b/arch/arm/boot/dts/gemini.dtsi
@@ -83,6 +83,19 @@
clock-names = "PCLK", "EXTCLK";
};
+ sata: sata@46000000 {
+ compatible = "cortina,gemini-sata-bridge";
+ reg = <0x46000000 0x100>;
+ resets = <&syscon GEMINI_RESET_SATA0>,
+ <&syscon GEMINI_RESET_SATA1>;
+ reset-names = "sata0", "sata1";
+ clocks = <&syscon GEMINI_CLK_GATE_SATA0>,
+ <&syscon GEMINI_CLK_GATE_SATA1>;
+ clock-names = "SATA0_PCLK", "SATA1_PCLK";
+ syscon = <&syscon>;
+ status = "disabled";
+ };
+
intcon: interrupt-controller@48000000 {
compatible = "faraday,ftintc010";
reg = <0x48000000 0x1000>;
@@ -178,6 +191,28 @@
};
};
+ ata@63000000 {
+ compatible = "cortina,gemini-pata", "faraday,ftide010";
+ reg = <0x63000000 0x1000>;
+ interrupts = <4 IRQ_TYPE_EDGE_RISING>;
+ resets = <&syscon GEMINI_RESET_IDE>;
+ clocks = <&syscon GEMINI_CLK_GATE_IDE>;
+ clock-names = "PCLK";
+ sata = <&sata>;
+ status = "disabled";
+ };
+
+ ata@63400000 {
+ compatible = "cortina,gemini-pata", "faraday,ftide010";
+ reg = <0x63400000 0x1000>;
+ interrupts = <5 IRQ_TYPE_EDGE_RISING>;
+ resets = <&syscon GEMINI_RESET_IDE>;
+ clocks = <&syscon GEMINI_CLK_GATE_IDE>;
+ clock-names = "PCLK";
+ sata = <&sata>;
+ status = "disabled";
+ };
+
dma-controller@67000000 {
compatible = "faraday,ftdma020", "arm,pl080", "arm,primecell";
/* Faraday Technology FTDMAC020 variant */
--
2.9.4
^ permalink raw reply related
* [PATCH 3/4 v4] ata: Add driver for Faraday Technology FTIDE010
From: Linus Walleij @ 2017-06-04 8:50 UTC (permalink / raw)
To: Tejun Heo, Bartlomiej Zolnierkiewicz, linux-ide
Cc: Janos Laube, Paulius Zaleckas, linux-arm-kernel, Hans Ulli Kroll,
Florian Fainelli, Linus Walleij, John Feng-Hsin Chiang,
Greentime Hu
In-Reply-To: <20170604085009.11902-1-linus.walleij@linaro.org>
This adds a driver for the Faraday Technology FTIDE010
PATA IP block.
When used with the Storlink/Storm/Cortina Systems Gemini
SoC, the PATA interface is accompanied by a PATA<->SATA
bridge, so while the device appear as a PATA controller,
it attaches physically to SATA disks, and also has a
designated memory area with registers to set up the bridge.
The Gemini SATA bridge is separated into its own driver
file to make things modular and make it possible to reuse
the PATA driver as stand-alone on other systems than the
Gemini.
dmesg excerpt from the D-Link DIR-685 storage router:
gemini-sata-bridge 46000000.sata: SATA ID 00000e00, PHY ID: 01000100
gemini-sata-bridge 46000000.sata: set up the Gemini IDE/SATA nexus
ftide010 63000000.ata: set up Gemini PATA0
ftide010 63000000.ata: device ID 00000500, irq 26, io base 0x63000000
ftide010 63000000.ata: SATA0 (master) start
gemini-sata-bridge 46000000.sata: SATA0 PHY ready
scsi host0: pata-ftide010
ata1: PATA max UDMA/133 irq 26
ata1.00: ATA-8: INTEL SSDSA2CW120G3, 4PC10302, max UDMA/133
ata1.00: 234441648 sectors, multi 1: LBA48 NCQ (depth 0/32)
ata1.00: configured for UDMA/133
scsi 0:0:0:0: Direct-Access ATA INTEL SSDSA2CW12 0302 PQ: 0 ANSI: 5
ata1.00: Enabling discard_zeroes_data
sd 0:0:0:0: [sda] 234441648 512-byte logical blocks: (120 GB/112 GiB)
sd 0:0:0:0: [sda] Write Protect is off
sd 0:0:0:0: [sda] Write cache: enabled, read cache:
enabled, doesn't support DPO or FUA
ata1.00: Enabling discard_zeroes_data
ata1.00: Enabling discard_zeroes_data
sd 0:0:0:0: [sda] Attached SCSI disk
After this I can flawlessly mount and read/write copy etc files
from /dev/sda[n].
Cc: John Feng-Hsin Chiang <john453@faraday-tech.com>
Cc: Greentime Hu <green.hu@gmail.com>
Acked-by: Hans Ulli Kroll <ulli.kroll@googlemail.com>
Signed-off-by: Linus Walleij <linus.walleij@linaro.org>
---
ChangeLog v3->v4:
- Switch timings when going from slave->master or master->slave
access using the .qc_issue() callback and storing the currently
active device (master or slave) in the active port private data.
- Use hardcoded timings instead of putting them in the
state container.
- Fix the clock disable/unprepare on the errorpath in the SATA
bridge portions.
- Use DRV_NAME throughout for name, driver name and alias.
- Prefix all defines with FTIDE010_* or GEMINI_* for clarity.
- Fix some u8 types.
- Replace an instance of iowrite8() with writeb() for consistency.
ChangeLog v2->v3:
- Remove the call to platform_set_drvdata() which was
overwriting the host pointer. Rely instead on
host->private_data like everyone else.
ChangeLog v1->v2:
- Drop the parsing of timings from the device tree, instead
keeping it in the driver, copying over the documentation
from the device tree and the nice structure so that
it's easy to modify for other SoCs.
- Some fixes to bail out from .port_start() if there is no
drive connected to the bridge, without us having to wait
for a timeout.
- Fix up the inclusion guard in the header file to be an
inclusion guard and not #ifdef CONFIG_FOO (which will anyways
not work for things compiled as module).
---
MAINTAINERS | 9 +
drivers/ata/Kconfig | 21 ++
drivers/ata/Makefile | 2 +
drivers/ata/pata_ftide010.c | 567 ++++++++++++++++++++++++++++++++++++++++++++
drivers/ata/sata_gemini.c | 438 ++++++++++++++++++++++++++++++++++
drivers/ata/sata_gemini.h | 21 ++
6 files changed, 1058 insertions(+)
create mode 100644 drivers/ata/pata_ftide010.c
create mode 100644 drivers/ata/sata_gemini.c
create mode 100644 drivers/ata/sata_gemini.h
diff --git a/MAINTAINERS b/MAINTAINERS
index f7d568b8f133..96753be12026 100644
--- a/MAINTAINERS
+++ b/MAINTAINERS
@@ -7531,6 +7531,15 @@ S: Maintained
F: drivers/ata/pata_*.c
F: drivers/ata/ata_generic.c
+LIBATA PATA FARADAY FTIDE010 AND GEMINI SATA BRIDGE DRIVERS
+M: Linus Walleij <linus.walleij@linaro.org>
+L: linux-ide@vger.kernel.org
+T: git git://git.kernel.org/pub/scm/linux/kernel/git/tj/libata.git
+S: Maintained
+F: drivers/ata/pata_ftide010.c
+F: drivers/ata/sata_gemini.c
+F: drivers/ata/sata_gemini.h
+
LIBATA SATA AHCI PLATFORM devices support
M: Hans de Goede <hdegoede@redhat.com>
M: Tejun Heo <tj@kernel.org>
diff --git a/drivers/ata/Kconfig b/drivers/ata/Kconfig
index de3eaf051697..948fc86980a1 100644
--- a/drivers/ata/Kconfig
+++ b/drivers/ata/Kconfig
@@ -213,6 +213,16 @@ config SATA_FSL
If unsure, say N.
+config SATA_GEMINI
+ tristate "Gemini SATA bridge support"
+ depends on PATA_FTIDE010
+ default ARCH_GEMINI
+ help
+ This enabled support for the FTIDE010 to SATA bridge
+ found in Cortina Systems Gemini platform.
+
+ If unsure, say N.
+
config SATA_AHCI_SEATTLE
tristate "AMD Seattle 6.0Gbps AHCI SATA host controller support"
depends on ARCH_SEATTLE
@@ -599,6 +609,17 @@ config PATA_EP93XX
If unsure, say N.
+config PATA_FTIDE010
+ tristate "Faraday Technology FTIDE010 PATA support"
+ depends on OF
+ depends on ARM
+ default ARCH_GEMINI
+ help
+ This option enables support for the Faraday FTIDE010
+ PATA controller found in the Cortina Gemini SoCs.
+
+ If unsure, say N.
+
config PATA_HPT366
tristate "HPT 366/368 PATA support"
depends on PCI
diff --git a/drivers/ata/Makefile b/drivers/ata/Makefile
index cd931a5eba92..a26ef5a93919 100644
--- a/drivers/ata/Makefile
+++ b/drivers/ata/Makefile
@@ -7,6 +7,7 @@ obj-$(CONFIG_SATA_ACARD_AHCI) += acard-ahci.o libahci.o
obj-$(CONFIG_SATA_AHCI_SEATTLE) += ahci_seattle.o libahci.o libahci_platform.o
obj-$(CONFIG_SATA_AHCI_PLATFORM) += ahci_platform.o libahci.o libahci_platform.o
obj-$(CONFIG_SATA_FSL) += sata_fsl.o
+obj-$(CONFIG_SATA_GEMINI) += sata_gemini.o
obj-$(CONFIG_SATA_INIC162X) += sata_inic162x.o
obj-$(CONFIG_SATA_SIL24) += sata_sil24.o
obj-$(CONFIG_SATA_DWC) += sata_dwc_460ex.o
@@ -60,6 +61,7 @@ obj-$(CONFIG_PATA_CS5536) += pata_cs5536.o
obj-$(CONFIG_PATA_CYPRESS) += pata_cypress.o
obj-$(CONFIG_PATA_EFAR) += pata_efar.o
obj-$(CONFIG_PATA_EP93XX) += pata_ep93xx.o
+obj-$(CONFIG_PATA_FTIDE010) += pata_ftide010.o
obj-$(CONFIG_PATA_HPT366) += pata_hpt366.o
obj-$(CONFIG_PATA_HPT37X) += pata_hpt37x.o
obj-$(CONFIG_PATA_HPT3X2N) += pata_hpt3x2n.o
diff --git a/drivers/ata/pata_ftide010.c b/drivers/ata/pata_ftide010.c
new file mode 100644
index 000000000000..7b7e417ba8ba
--- /dev/null
+++ b/drivers/ata/pata_ftide010.c
@@ -0,0 +1,567 @@
+/*
+ * Faraday Technology FTIDE010 driver
+ * Copyright (C) 2017 Linus Walleij <linus.walleij@linaro.org>
+ *
+ * Includes portions of the SL2312/SL3516/Gemini PATA driver
+ * Copyright (C) 2003 StorLine, Inc <jason@storlink.com.tw>
+ * Copyright (C) 2009 Janos Laube <janos.dev@gmail.com>
+ * Copyright (C) 2010 Frederic Pecourt <opengemini@free.fr>
+ * Copyright (C) 2011 Tobias Waldvogel <tobias.waldvogel@gmail.com>
+ */
+
+#include <linux/platform_device.h>
+#include <linux/module.h>
+#include <linux/libata.h>
+#include <linux/bitops.h>
+#include <linux/of_address.h>
+#include <linux/of_device.h>
+#include <linux/clk.h>
+#include "sata_gemini.h"
+
+#define DRV_NAME "pata_ftide010"
+
+/**
+ * struct ftide010 - state container for the Faraday FTIDE010
+ * @dev: pointer back to the device representing this controller
+ * @base: remapped I/O space address
+ * @pclk: peripheral clock for the IDE block
+ * @host: pointer to the ATA host for this device
+ * @master_cbl: master cable type
+ * @slave_cbl: slave cable type
+ * @sg: Gemini SATA bridge pointer, if running on the Gemini
+ * @master_to_sata0: Gemini SATA bridge: the ATA master is connected
+ * to the SATA0 bridge
+ * @slave_to_sata0: Gemini SATA bridge: the ATA slave is connected
+ * to the SATA0 bridge
+ * @master_to_sata1: Gemini SATA bridge: the ATA master is connected
+ * to the SATA1 bridge
+ * @slave_to_sata1: Gemini SATA bridge: the ATA slave is connected
+ * to the SATA1 bridge
+ */
+struct ftide010 {
+ struct device *dev;
+ void __iomem *base;
+ struct clk *pclk;
+ struct ata_host *host;
+ unsigned int master_cbl;
+ unsigned int slave_cbl;
+ /* Gemini-specific properties */
+ struct sata_gemini *sg;
+ bool master_to_sata0;
+ bool slave_to_sata0;
+ bool master_to_sata1;
+ bool slave_to_sata1;
+};
+
+#define FTIDE010_DMA_REG 0x00
+#define FTIDE010_DMA_STATUS 0x02
+#define FTIDE010_IDE_BMDTPR 0x04
+#define FTIDE010_IDE_DEVICE_ID 0x08
+#define FTIDE010_PIO_TIMING 0x10
+#define FTIDE010_MWDMA_TIMING 0x11
+#define FTIDE010_UDMA_TIMING0 0x12 /* Master */
+#define FTIDE010_UDMA_TIMING1 0x13 /* Slave */
+#define FTIDE010_CLK_MOD 0x14
+/* These registers are mapped directly to the IDE registers */
+#define FTIDE010_CMD_DATA 0x20
+#define FTIDE010_ERROR_FEATURES 0x21
+#define FTIDE010_NSECT 0x22
+#define FTIDE010_LBAL 0x23
+#define FTIDE010_LBAM 0x24
+#define FTIDE010_LBAH 0x25
+#define FTIDE010_DEVICE 0x26
+#define FTIDE010_STATUS_COMMAND 0x27
+#define FTIDE010_ALTSTAT_CTRL 0x36
+
+/* Set this bit for UDMA mode 5 and 6 */
+#define FTIDE010_UDMA_TIMING_MODE_56 BIT(7)
+
+/* 0 = 50 MHz, 1 = 66 MHz */
+#define FTIDE010_CLK_MOD_DEV0_CLK_SEL BIT(0)
+#define FTIDE010_CLK_MOD_DEV1_CLK_SEL BIT(1)
+/* Enable UDMA on a device */
+#define FTIDE010_CLK_MOD_DEV0_UDMA_EN BIT(4)
+#define FTIDE010_CLK_MOD_DEV1_UDMA_EN BIT(5)
+
+static struct scsi_host_template pata_ftide010_sht = {
+ ATA_BMDMA_SHT(DRV_NAME),
+};
+
+/*
+ * Bus timings
+ *
+ * The unit of the below required timings is two clock periods of the ATA
+ * reference clock which is 30 nanoseconds per unit at 66MHz and 20
+ * nanoseconds per unit at 50 MHz. The PIO timings assume 33MHz speed for
+ * PIO.
+ *
+ * pio_active_time: array of 5 elements for T2 timing for Mode 0,
+ * 1, 2, 3 and 4. Range 0..15.
+ * pio_recovery_time: array of 5 elements for T2l timing for Mode 0,
+ * 1, 2, 3 and 4. Range 0..15.
+ * mdma_50_active_time: array of 4 elements for Td timing for multi
+ * word DMA, Mode 0, 1, and 2 at 50 MHz. Range 0..15.
+ * mdma_50_recovery_time: array of 4 elements for Tk timing for
+ * multi word DMA, Mode 0, 1 and 2 at 50 MHz. Range 0..15.
+ * mdma_66_active_time: array of 4 elements for Td timing for multi
+ * word DMA, Mode 0, 1 and 2 at 66 MHz. Range 0..15.
+ * mdma_66_recovery_time: array of 4 elements for Tk timing for
+ * multi word DMA, Mode 0, 1 and 2 at 66 MHz. Range 0..15.
+ * udma_50_setup_time: array of 4 elements for Tvds timing for ultra
+ * DMA, Mode 0, 1, 2, 3, 4 and 5 at 50 MHz. Range 0..7.
+ * udma_50_hold_time: array of 4 elements for Tdvh timing for
+ * multi word DMA, Mode 0, 1, 2, 3, 4 and 5 at 50 MHz, Range 0..7.
+ * udma_66_setup_time: array of 4 elements for Tvds timing for multi
+ * word DMA, Mode 0, 1, 2, 3, 4, 5 and 6 at 66 MHz. Range 0..7.
+ * udma_66_hold_time: array of 4 elements for Tdvh timing for
+ * multi word DMA, Mode 0, 1, 2, 3, 4, 5 and 6 at 66 MHz. Range 0..7.
+ */
+static const u8 pio_active_time[5] = {10, 10, 10, 3, 3};
+static const u8 pio_recovery_time[5] = {10, 3, 1, 3, 1};
+static const u8 mwdma_50_active_time[3] = {6, 2, 2};
+static const u8 mwdma_50_recovery_time[3] = {6, 2, 1};
+static const u8 mwdma_66_active_time[3] = {8, 3, 3};
+static const u8 mwdma_66_recovery_time[3] = {8, 2, 1};
+static const u8 udma_50_setup_time[6] = {3, 3, 2, 2, 1, 1};
+static const u8 udma_50_hold_time[6] = {3, 1, 1, 1, 1, 1};
+static const u8 udma_66_setup_time[7] = {4, 4, 3, 2, };
+static const u8 udma_66_hold_time[7] = {};
+
+/*
+ * We set 66 MHz for all MWDMA modes
+ */
+static const bool set_mdma_66_mhz[] = { true, true, true, true };
+
+/*
+ * We set 66 MHz for UDMA modes 3, 4 and 6 and no others
+ */
+static const bool set_udma_66_mhz[] = { false, false, false, true, true, false, true };
+
+static void ftide010_set_dmamode(struct ata_port *ap, struct ata_device *adev)
+{
+ struct ftide010 *ftide = ap->host->private_data;
+ u8 speed = adev->dma_mode;
+ u8 devno = adev->devno & 1;
+ u8 udma_en_mask;
+ u8 f66m_en_mask;
+ u8 clkreg;
+ u8 timreg;
+ u8 i;
+
+ /* Target device 0 (master) or 1 (slave) */
+ if (!devno) {
+ udma_en_mask = FTIDE010_CLK_MOD_DEV0_UDMA_EN;
+ f66m_en_mask = FTIDE010_CLK_MOD_DEV0_CLK_SEL;
+ } else {
+ udma_en_mask = FTIDE010_CLK_MOD_DEV1_UDMA_EN;
+ f66m_en_mask = FTIDE010_CLK_MOD_DEV1_CLK_SEL;
+ }
+
+ clkreg = readb(ftide->base + FTIDE010_CLK_MOD);
+ clkreg &= ~udma_en_mask;
+ clkreg &= ~f66m_en_mask;
+
+ if (speed & XFER_UDMA_0) {
+ i = speed & ~XFER_UDMA_0;
+ dev_dbg(ftide->dev, "set UDMA mode %02x, index %d\n",
+ speed, i);
+
+ clkreg |= udma_en_mask;
+ if (set_udma_66_mhz[i]) {
+ clkreg |= f66m_en_mask;
+ timreg = udma_66_setup_time[i] << 4 |
+ udma_66_hold_time[i];
+ } else {
+ timreg = udma_50_setup_time[i] << 4 |
+ udma_50_hold_time[i];
+ }
+
+ /* A special bit needs to be set for modes 5 and 6 */
+ if (i >= 5)
+ timreg |= FTIDE010_UDMA_TIMING_MODE_56;
+
+ dev_dbg(ftide->dev, "UDMA write clkreg = %02x, timreg = %02x\n",
+ clkreg, timreg);
+
+ writeb(clkreg, ftide->base + FTIDE010_CLK_MOD);
+ writeb(timreg, ftide->base + FTIDE010_UDMA_TIMING0 + devno);
+ } else {
+ i = speed & ~XFER_MW_DMA_0;
+ dev_dbg(ftide->dev, "set MWDMA mode %02x, index %d\n",
+ speed, i);
+
+ if (set_mdma_66_mhz[i]) {
+ clkreg |= f66m_en_mask;
+ timreg = mwdma_66_active_time[i] << 4 |
+ mwdma_66_recovery_time[i];
+ } else {
+ timreg = mwdma_50_active_time[i] << 4 |
+ mwdma_50_recovery_time[i];
+ }
+ dev_dbg(ftide->dev,
+ "MWDMA write clkreg = %02x, timreg = %02x\n",
+ clkreg, timreg);
+ /* This will affect all devices */
+ writeb(clkreg, ftide->base + FTIDE010_CLK_MOD);
+ writeb(timreg, ftide->base + FTIDE010_MWDMA_TIMING);
+ }
+
+ /*
+ * Store the current device (master or slave) in ap->private_data
+ * so that .qc_issue() can detect if this changes and reprogram
+ * the DMA settings.
+ */
+ ap->private_data = adev;
+
+ return;
+}
+
+static void ftide010_set_piomode(struct ata_port *ap, struct ata_device *adev)
+{
+ struct ftide010 *ftide = ap->host->private_data;
+ u8 pio = adev->pio_mode - XFER_PIO_0;
+
+ dev_dbg(ftide->dev, "set PIO mode %02x, index %d\n",
+ adev->pio_mode, pio);
+ writeb(pio_active_time[pio] << 4 | pio_recovery_time[pio],
+ ftide->base + FTIDE010_PIO_TIMING);
+}
+
+/*
+ * We implement our own qc_issue() callback since we may need to set up
+ * the timings differently for master and slave transfers: the CLK_MOD_REG
+ * and MWDMA_TIMING_REG is shared between master and slave, so reprogramming
+ * this may be necessary.
+ */
+static unsigned int ftide010_qc_issue(struct ata_queued_cmd *qc)
+{
+ struct ata_port *ap = qc->ap;
+ struct ata_device *adev = qc->dev;
+
+ /*
+ * If the device changed, i.e. slave->master, master->slave,
+ * then set up the DMA mode again so we are sure the timings
+ * are correct.
+ */
+ if (adev != ap->private_data && ata_dma_enabled(adev))
+ ftide010_set_dmamode(ap, adev);
+
+ return ata_bmdma_qc_issue(qc);
+}
+
+static struct ata_port_operations pata_ftide010_port_ops = {
+ .inherits = &ata_bmdma_port_ops,
+ .set_dmamode = ftide010_set_dmamode,
+ .set_piomode = ftide010_set_piomode,
+ .qc_issue = ftide010_qc_issue,
+};
+
+static struct ata_port_info ftide010_port_info[] = {
+ {
+ .flags = ATA_FLAG_SLAVE_POSS,
+ .mwdma_mask = ATA_MWDMA2,
+ .udma_mask = ATA_UDMA6,
+ .pio_mask = ATA_PIO4,
+ .port_ops = &pata_ftide010_port_ops,
+ },
+};
+
+#if IS_ENABLED(CONFIG_SATA_GEMINI)
+
+static int pata_ftide010_gemini_port_start(struct ata_port *ap)
+{
+ struct ftide010 *ftide = ap->host->private_data;
+ struct device *dev = ftide->dev;
+ struct sata_gemini *sg = ftide->sg;
+ int bridges = 0;
+ int ret;
+
+ ret = ata_bmdma_port_start(ap);
+ if (ret)
+ return ret;
+
+ if (ftide->master_to_sata0) {
+ dev_info(dev, "SATA0 (master) start\n");
+ ret = gemini_sata_start_bridge(sg, 0);
+ if (!ret)
+ bridges++;
+ }
+ if (ftide->master_to_sata1) {
+ dev_info(dev, "SATA1 (master) start\n");
+ ret = gemini_sata_start_bridge(sg, 1);
+ if (!ret)
+ bridges++;
+ }
+ /* Avoid double-starting */
+ if (ftide->slave_to_sata0 && !ftide->master_to_sata0) {
+ dev_info(dev, "SATA0 (slave) start\n");
+ ret = gemini_sata_start_bridge(sg, 0);
+ if (!ret)
+ bridges++;
+ }
+ /* Avoid double-starting */
+ if (ftide->slave_to_sata1 && !ftide->master_to_sata1) {
+ dev_info(dev, "SATA1 (slave) start\n");
+ ret = gemini_sata_start_bridge(sg, 1);
+ if (!ret)
+ bridges++;
+ }
+
+ dev_info(dev, "brought %d bridges online\n", bridges);
+ return (bridges > 0) ? 0 : -EINVAL; // -ENODEV;
+}
+
+static void pata_ftide010_gemini_port_stop(struct ata_port *ap)
+{
+ struct ftide010 *ftide = ap->host->private_data;
+ struct device *dev = ftide->dev;
+ struct sata_gemini *sg = ftide->sg;
+
+ if (ftide->master_to_sata0) {
+ dev_info(dev, "SATA0 (master) stop\n");
+ gemini_sata_stop_bridge(sg, 0);
+ }
+ if (ftide->master_to_sata1) {
+ dev_info(dev, "SATA1 (master) stop\n");
+ gemini_sata_stop_bridge(sg, 1);
+ }
+ /* Avoid double-stopping */
+ if (ftide->slave_to_sata0 && !ftide->master_to_sata0) {
+ dev_info(dev, "SATA0 (slave) stop\n");
+ gemini_sata_stop_bridge(sg, 0);
+ }
+ /* Avoid double-stopping */
+ if (ftide->slave_to_sata1 && !ftide->master_to_sata1) {
+ dev_info(dev, "SATA1 (slave) stop\n");
+ gemini_sata_stop_bridge(sg, 1);
+ }
+}
+
+static int pata_ftide010_gemini_cable_detect(struct ata_port *ap)
+{
+ struct ftide010 *ftide = ap->host->private_data;
+
+ /*
+ * Return the master cable, I have no clue how to return a different
+ * cable for the slave than for the master.
+ */
+ return ftide->master_cbl;
+}
+
+static int pata_ftide010_gemini_init(struct ftide010 *ftide,
+ bool is_ata1)
+{
+ struct device *dev = ftide->dev;
+ struct sata_gemini *sg;
+ enum gemini_muxmode muxmode;
+
+ /* Look up SATA bridge */
+ sg = gemini_sata_bridge_get();
+ if (IS_ERR(sg))
+ return PTR_ERR(sg);
+ ftide->sg = sg;
+
+ muxmode = gemini_sata_get_muxmode(sg);
+
+ /* Special ops */
+ pata_ftide010_port_ops.port_start =
+ pata_ftide010_gemini_port_start;
+ pata_ftide010_port_ops.port_stop =
+ pata_ftide010_gemini_port_stop;
+ pata_ftide010_port_ops.cable_detect =
+ pata_ftide010_gemini_cable_detect;
+
+ /* Flag port as SATA-capable */
+ if (gemini_sata_bridge_enabled(sg, is_ata1))
+ ftide010_port_info[0].flags |= ATA_FLAG_SATA;
+
+ /*
+ * We assume that a simple 40-wire cable is used in the PATA mode.
+ * if you're adding a system using the PATA interface, make sure
+ * the right cable is set up here, it might be necessary to use
+ * special hardware detection or encode the cable type in the device
+ * tree with special properties.
+ */
+ if (!is_ata1) {
+ switch (muxmode) {
+ case GEMINI_MUXMODE_0:
+ ftide->master_cbl = ATA_CBL_SATA;
+ ftide->slave_cbl = ATA_CBL_PATA40;
+ ftide->master_to_sata0 = true;
+ break;
+ case GEMINI_MUXMODE_1:
+ ftide->master_cbl = ATA_CBL_SATA;
+ ftide->slave_cbl = ATA_CBL_NONE;
+ ftide->master_to_sata0 = true;
+ break;
+ case GEMINI_MUXMODE_2:
+ ftide->master_cbl = ATA_CBL_PATA40;
+ ftide->slave_cbl = ATA_CBL_PATA40;
+ break;
+ case GEMINI_MUXMODE_3:
+ ftide->master_cbl = ATA_CBL_SATA;
+ ftide->slave_cbl = ATA_CBL_SATA;
+ ftide->master_to_sata0 = true;
+ ftide->slave_to_sata1 = true;
+ break;
+ }
+ } else {
+ switch (muxmode) {
+ case GEMINI_MUXMODE_0:
+ ftide->master_cbl = ATA_CBL_SATA;
+ ftide->slave_cbl = ATA_CBL_NONE;
+ ftide->master_to_sata1 = true;
+ break;
+ case GEMINI_MUXMODE_1:
+ ftide->master_cbl = ATA_CBL_SATA;
+ ftide->slave_cbl = ATA_CBL_PATA40;
+ ftide->master_to_sata1 = true;
+ break;
+ case GEMINI_MUXMODE_2:
+ ftide->master_cbl = ATA_CBL_SATA;
+ ftide->slave_cbl = ATA_CBL_SATA;
+ ftide->slave_to_sata0 = true;
+ ftide->master_to_sata1 = true;
+ break;
+ case GEMINI_MUXMODE_3:
+ ftide->master_cbl = ATA_CBL_PATA40;
+ ftide->slave_cbl = ATA_CBL_PATA40;
+ break;
+ }
+ }
+ dev_info(dev, "set up Gemini PATA%d\n", is_ata1);
+
+ return 0;
+}
+#else
+static int pata_ftide010_gemini_init(struct ftide010 *ftide,
+ bool is_ata1)
+{
+ return -ENOTSUPP;
+}
+#endif
+
+
+static int pata_ftide010_probe(struct platform_device *pdev)
+{
+ struct device *dev = &pdev->dev;
+ struct device_node *np = dev->of_node;
+ const struct ata_port_info pi = ftide010_port_info[0];
+ const struct ata_port_info *ppi[] = { &pi, NULL };
+ struct ftide010 *ftide;
+ struct resource *res;
+ int irq;
+ int ret;
+ int i;
+
+ ftide = devm_kzalloc(dev, sizeof(*ftide), GFP_KERNEL);
+ if (!ftide)
+ return -ENOMEM;
+ ftide->dev = dev;
+
+ irq = platform_get_irq(pdev, 0);
+ if (irq < 0)
+ return irq;
+
+ res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+ if (!res)
+ return -ENODEV;
+
+ ftide->base = devm_ioremap_resource(dev, res);
+ if (IS_ERR(ftide->base))
+ return PTR_ERR(ftide->base);
+
+ ftide->pclk = devm_clk_get(dev, "PCLK");
+ if (!IS_ERR(ftide->pclk)) {
+ ret = clk_prepare_enable(ftide->pclk);
+ if (ret) {
+ dev_err(dev, "failed to enable PCLK\n");
+ return ret;
+ }
+ }
+
+ /* Some special Cortina Gemini init, if needed */
+ if (of_device_is_compatible(np, "cortina,gemini-pata")) {
+ /*
+ * We need to know which instance is probing (the
+ * Gemini has two instances of FTIDE010) and we do
+ * this simply by looking at the physical base
+ * address, which is 0x63400000 for ATA1, else we
+ * are ATA0. This will also set up the cable types.
+ */
+ ret = pata_ftide010_gemini_init(ftide,
+ (res->start == 0x63400000));
+ if (ret)
+ goto err_dis_clk;
+ } else {
+ /* Else assume we are connected using PATA40 */
+ ftide->master_cbl = ATA_CBL_PATA40;
+ ftide->slave_cbl = ATA_CBL_PATA40;
+ }
+
+ ftide->host = ata_host_alloc_pinfo(dev, ppi, 1);
+ if (!ftide->host) {
+ ret = -ENOMEM;
+ goto err_dis_clk;
+ }
+ ftide->host->private_data = ftide;
+
+ for (i = 0; i < ftide->host->n_ports; i++) {
+ struct ata_port *ap = ftide->host->ports[i];
+ struct ata_ioports *ioaddr = &ap->ioaddr;
+
+ ioaddr->bmdma_addr = ftide->base + FTIDE010_DMA_REG;
+ ioaddr->cmd_addr = ftide->base + FTIDE010_CMD_DATA;
+ ioaddr->ctl_addr = ftide->base + FTIDE010_ALTSTAT_CTRL;
+ ioaddr->altstatus_addr = ftide->base + FTIDE010_ALTSTAT_CTRL;
+ ata_sff_std_ports(ioaddr);
+ }
+
+ dev_info(dev, "device ID %08x, irq %d, io base 0x%08x\n",
+ readl(ftide->base + FTIDE010_IDE_DEVICE_ID), irq, res->start);
+
+ ret = ata_host_activate(ftide->host, irq, ata_bmdma_interrupt,
+ 0, &pata_ftide010_sht);
+ if (ret)
+ goto err_dis_clk;
+
+ return 0;
+
+err_dis_clk:
+ if (!IS_ERR(ftide->pclk))
+ clk_disable_unprepare(ftide->pclk);
+ return ret;
+}
+
+static int pata_ftide010_remove(struct platform_device *pdev)
+{
+ struct ata_host *host = platform_get_drvdata(pdev);
+ struct ftide010 *ftide = host->private_data;
+
+ ata_host_detach(ftide->host);
+ if (!IS_ERR(ftide->pclk))
+ clk_disable_unprepare(ftide->pclk);
+
+ return 0;
+}
+
+static const struct of_device_id pata_ftide010_of_match[] = {
+ {
+ .compatible = "faraday,ftide010",
+ },
+ {},
+};
+
+static struct platform_driver pata_ftide010_driver = {
+ .driver = {
+ .name = DRV_NAME,
+ .of_match_table = of_match_ptr(pata_ftide010_of_match),
+ },
+ .probe = pata_ftide010_probe,
+ .remove = pata_ftide010_remove,
+};
+module_platform_driver(pata_ftide010_driver);
+
+MODULE_AUTHOR("Linus Walleij <linus.walleij@linaro.org>");
+MODULE_LICENSE("GPL");
+MODULE_ALIAS("platform:" DRV_NAME);
diff --git a/drivers/ata/sata_gemini.c b/drivers/ata/sata_gemini.c
new file mode 100644
index 000000000000..8c704523bae7
--- /dev/null
+++ b/drivers/ata/sata_gemini.c
@@ -0,0 +1,438 @@
+/*
+ * Cortina Systems Gemini SATA bridge add-on to Faraday FTIDE010
+ * Copyright (C) 2017 Linus Walleij <linus.walleij@linaro.org>
+ */
+
+#include <linux/init.h>
+#include <linux/module.h>
+#include <linux/platform_device.h>
+#include <linux/bitops.h>
+#include <linux/mfd/syscon.h>
+#include <linux/regmap.h>
+#include <linux/delay.h>
+#include <linux/reset.h>
+#include <linux/of_address.h>
+#include <linux/of_device.h>
+#include <linux/clk.h>
+#include <linux/io.h>
+#include "sata_gemini.h"
+
+#define DRV_NAME "gemini_sata_bridge"
+
+/**
+ * struct sata_gemini - a state container for a Gemini SATA bridge
+ * @dev: the containing device
+ * @base: remapped I/O memory base
+ * @muxmode: the current muxing mode
+ * @ide_pins: if the device is using the plain IDE interface pins
+ * @sata_bridge: if the device enables the SATA bridge
+ * @sata0_reset: SATA0 reset handler
+ * @sata1_reset: SATA1 reset handler
+ * @sata0_pclk: SATA0 PCLK handler
+ * @sata1_pclk: SATA1 PCLK handler
+ */
+struct sata_gemini {
+ struct device *dev;
+ void __iomem *base;
+ enum gemini_muxmode muxmode;
+ bool ide_pins;
+ bool sata_bridge;
+ struct reset_control *sata0_reset;
+ struct reset_control *sata1_reset;
+ struct clk *sata0_pclk;
+ struct clk *sata1_pclk;
+};
+
+/* Global IDE PAD Skew Control Register */
+#define GEMINI_GLOBAL_IDE_SKEW_CTRL 0x18
+#define GEMINI_IDE1_HOST_STROBE_DELAY_SHIFT 28
+#define GEMINI_IDE1_DEVICE_STROBE_DELAY_SHIFT 24
+#define GEMINI_IDE1_OUTPUT_IO_SKEW_SHIFT 20
+#define GEMINI_IDE1_INPUT_IO_SKEW_SHIFT 16
+#define GEMINI_IDE0_HOST_STROBE_DELAY_SHIFT 12
+#define GEMINI_IDE0_DEVICE_STROBE_DELAY_SHIFT 8
+#define GEMINI_IDE0_OUTPUT_IO_SKEW_SHIFT 4
+#define GEMINI_IDE0_INPUT_IO_SKEW_SHIFT 0
+
+/* Miscellaneous Control Register */
+#define GEMINI_GLOBAL_MISC_CTRL 0x30
+/*
+ * Values of IDE IOMUX bits in the misc control register
+ *
+ * Bits 26:24 are "IDE IO Select", which decides what SATA
+ * adapters are connected to which of the two IDE/ATA
+ * controllers in the Gemini. We can connect the two IDE blocks
+ * to one SATA adapter each, both acting as master, or one IDE
+ * blocks to two SATA adapters so the IDE block can act in a
+ * master/slave configuration.
+ *
+ * We also bring out different blocks on the actual IDE
+ * pins (not SATA pins) if (and only if) these are muxed in.
+ *
+ * 111-100 - Reserved
+ * Mode 0: 000 - ata0 master <-> sata0
+ * ata1 master <-> sata1
+ * ata0 slave interface brought out on IDE pads
+ * Mode 1: 001 - ata0 master <-> sata0
+ * ata1 master <-> sata1
+ * ata1 slave interface brought out on IDE pads
+ * Mode 2: 010 - ata1 master <-> sata1
+ * ata1 slave <-> sata0
+ * ata0 master and slave interfaces brought out
+ * on IDE pads
+ * Mode 3: 011 - ata0 master <-> sata0
+ * ata1 slave <-> sata1
+ * ata1 master and slave interfaces brought out
+ * on IDE pads
+ */
+#define GEMINI_IDE_IOMUX_MASK (7 << 24)
+#define GEMINI_IDE_IOMUX_MODE0 (0 << 24)
+#define GEMINI_IDE_IOMUX_MODE1 (1 << 24)
+#define GEMINI_IDE_IOMUX_MODE2 (2 << 24)
+#define GEMINI_IDE_IOMUX_MODE3 (3 << 24)
+#define GEMINI_IDE_IOMUX_SHIFT (24)
+#define GEMINI_IDE_PADS_ENABLE BIT(4)
+#define GEMINI_PFLASH_PADS_DISABLE BIT(1)
+
+/*
+ * Registers directly controlling the PATA<->SATA adapters
+ */
+#define GEMINI_SATA_ID 0x00
+#define GEMINI_SATA_PHY_ID 0x04
+#define GEMINI_SATA0_STATUS 0x08
+#define GEMINI_SATA1_STATUS 0x0c
+#define GEMINI_SATA0_CTRL 0x18
+#define GEMINI_SATA1_CTRL 0x1c
+
+#define GEMINI_SATA_STATUS_BIST_DONE BIT(5)
+#define GEMINI_SATA_STATUS_BIST_OK BIT(4)
+#define GEMINI_SATA_STATUS_PHY_READY BIT(0)
+
+#define GEMINI_SATA_CTRL_PHY_BIST_EN BIT(14)
+#define GEMINI_SATA_CTRL_PHY_FORCE_IDLE BIT(13)
+#define GEMINI_SATA_CTRL_PHY_FORCE_READY BIT(12)
+#define GEMINI_SATA_CTRL_PHY_AFE_LOOP_EN BIT(10)
+#define GEMINI_SATA_CTRL_PHY_DIG_LOOP_EN BIT(9)
+#define GEMINI_SATA_CTRL_HOTPLUG_DETECT_EN BIT(4)
+#define GEMINI_SATA_CTRL_ATAPI_EN BIT(3)
+#define GEMINI_SATA_CTRL_BUS_WITH_20 BIT(2)
+#define GEMINI_SATA_CTRL_SLAVE_EN BIT(1)
+#define GEMINI_SATA_CTRL_EN BIT(0)
+
+/*
+ * There is only ever one instance of this bridge on a system,
+ * so create a singleton so that the FTIDE010 instances can grab
+ * a reference to it.
+ */
+static struct sata_gemini *sg_singleton;
+
+struct sata_gemini *gemini_sata_bridge_get(void)
+{
+ if (sg_singleton)
+ return sg_singleton;
+ return ERR_PTR(-EPROBE_DEFER);
+}
+EXPORT_SYMBOL(gemini_sata_bridge_get);
+
+bool gemini_sata_bridge_enabled(struct sata_gemini *sg, bool is_ata1)
+{
+ if (!sg->sata_bridge)
+ return false;
+ /*
+ * In muxmode 2 and 3 one of the ATA controllers is
+ * actually not connected to any SATA bridge.
+ */
+ if ((sg->muxmode == GEMINI_MUXMODE_2) &&
+ !is_ata1)
+ return false;
+ if ((sg->muxmode == GEMINI_MUXMODE_3) &&
+ is_ata1)
+ return false;
+
+ return true;
+}
+EXPORT_SYMBOL(gemini_sata_bridge_enabled);
+
+enum gemini_muxmode gemini_sata_get_muxmode(struct sata_gemini *sg)
+{
+ return sg->muxmode;
+}
+EXPORT_SYMBOL(gemini_sata_get_muxmode);
+
+static int gemini_sata_setup_bridge(struct sata_gemini *sg,
+ unsigned int bridge)
+{
+ unsigned long timeout = jiffies + (HZ * 1);
+ bool bridge_online;
+ u32 val;
+
+ if (bridge == 0) {
+ val = GEMINI_SATA_CTRL_HOTPLUG_DETECT_EN | GEMINI_SATA_CTRL_EN;
+ /* SATA0 slave mode is only used in muxmode 2 */
+ if (sg->muxmode == GEMINI_MUXMODE_2)
+ val |= GEMINI_SATA_CTRL_SLAVE_EN;
+ writel(val, sg->base + GEMINI_SATA0_CTRL);
+ } else {
+ val = GEMINI_SATA_CTRL_HOTPLUG_DETECT_EN | GEMINI_SATA_CTRL_EN;
+ /* SATA1 slave mode is only used in muxmode 3 */
+ if (sg->muxmode == GEMINI_MUXMODE_3)
+ val |= GEMINI_SATA_CTRL_SLAVE_EN;
+ writel(val, sg->base + GEMINI_SATA1_CTRL);
+ }
+
+ /* Vendor code waits 10 ms here */
+ msleep(10);
+
+ /* Wait for PHY to become ready */
+ do {
+ msleep(100);
+
+ if (bridge == 0)
+ val = readl(sg->base + GEMINI_SATA0_STATUS);
+ else
+ val = readl(sg->base + GEMINI_SATA1_STATUS);
+ if (val & GEMINI_SATA_STATUS_PHY_READY)
+ break;
+ } while (time_before(jiffies, timeout));
+
+ bridge_online = !!(val & GEMINI_SATA_STATUS_PHY_READY);
+
+ dev_info(sg->dev, "SATA%d PHY %s\n", bridge,
+ bridge_online ? "ready" : "not ready");
+
+ return bridge_online ? 0: -ENODEV;
+}
+
+int gemini_sata_start_bridge(struct sata_gemini *sg, unsigned int bridge)
+{
+ struct clk *pclk;
+ int ret;
+
+ if (bridge == 0)
+ pclk = sg->sata0_pclk;
+ else
+ pclk = sg->sata1_pclk;
+ clk_enable(pclk);
+ msleep(10);
+
+ /* Do not keep clocking a bridge that is not online */
+ ret = gemini_sata_setup_bridge(sg, bridge);
+ if (ret)
+ clk_disable(pclk);
+
+ return ret;
+}
+EXPORT_SYMBOL(gemini_sata_start_bridge);
+
+void gemini_sata_stop_bridge(struct sata_gemini *sg, unsigned int bridge)
+{
+ if (bridge == 0)
+ clk_disable(sg->sata0_pclk);
+ else if (bridge == 1)
+ clk_disable(sg->sata1_pclk);
+}
+EXPORT_SYMBOL(gemini_sata_stop_bridge);
+
+int gemini_sata_reset_bridge(struct sata_gemini *sg,
+ unsigned int bridge)
+{
+ if (bridge == 0)
+ reset_control_reset(sg->sata0_reset);
+ else
+ reset_control_reset(sg->sata1_reset);
+ msleep(10);
+ return gemini_sata_setup_bridge(sg, bridge);
+}
+EXPORT_SYMBOL(gemini_sata_reset_bridge);
+
+static int gemini_sata_bridge_init(struct sata_gemini *sg)
+{
+ struct device *dev = sg->dev;
+ u32 sata_id, sata_phy_id;
+ int ret;
+
+ sg->sata0_pclk = devm_clk_get(dev, "SATA0_PCLK");
+ if (IS_ERR(sg->sata0_pclk)) {
+ dev_err(dev, "no SATA0 PCLK");
+ return -ENODEV;
+ }
+ sg->sata1_pclk = devm_clk_get(dev, "SATA1_PCLK");
+ if (IS_ERR(sg->sata1_pclk)) {
+ dev_err(dev, "no SATA1 PCLK");
+ return -ENODEV;
+ }
+
+ ret = clk_prepare_enable(sg->sata0_pclk);
+ if (ret) {
+ pr_err("failed to enable SATA0 PCLK\n");
+ return ret;
+ }
+ ret = clk_prepare_enable(sg->sata1_pclk);
+ if (ret) {
+ pr_err("failed to enable SATA1 PCLK\n");
+ clk_disable_unprepare(sg->sata0_pclk);
+ return ret;
+ }
+
+ sg->sata0_reset = devm_reset_control_get(dev, "sata0");
+ if (IS_ERR(sg->sata0_reset)) {
+ dev_err(dev, "no SATA0 reset controller\n");
+ clk_disable_unprepare(sg->sata1_pclk);
+ clk_disable_unprepare(sg->sata0_pclk);
+ return PTR_ERR(sg->sata0_reset);
+ }
+ sg->sata1_reset = devm_reset_control_get(dev, "sata1");
+ if (IS_ERR(sg->sata1_reset)) {
+ dev_err(dev, "no SATA1 reset controller\n");
+ clk_disable_unprepare(sg->sata1_pclk);
+ clk_disable_unprepare(sg->sata0_pclk);
+ return PTR_ERR(sg->sata1_reset);
+ }
+
+ sata_id = readl(sg->base + GEMINI_SATA_ID);
+ sata_phy_id = readl(sg->base + GEMINI_SATA_PHY_ID);
+ sg->sata_bridge = true;
+ clk_disable(sg->sata0_pclk);
+ clk_disable(sg->sata1_pclk);
+
+ dev_info(dev, "SATA ID %08x, PHY ID: %08x\n", sata_id, sata_phy_id);
+
+ return 0;
+}
+
+static int gemini_sata_probe(struct platform_device *pdev)
+{
+ struct device *dev = &pdev->dev;
+ struct device_node *np = dev->of_node;
+ struct sata_gemini *sg;
+ static struct regmap *map;
+ struct resource *res;
+ enum gemini_muxmode muxmode;
+ u32 gmode;
+ u32 gmask;
+ u32 val;
+ int ret;
+
+ sg = devm_kzalloc(dev, sizeof(*sg), GFP_KERNEL);
+ if (!sg)
+ return -ENOMEM;
+ sg->dev = dev;
+
+ res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+ if (!res)
+ return -ENODEV;
+
+ sg->base = devm_ioremap_resource(dev, res);
+ if (IS_ERR(sg->base))
+ return PTR_ERR(sg->base);
+
+ map = syscon_regmap_lookup_by_phandle(np, "syscon");
+ if (IS_ERR(map)) {
+ dev_err(dev, "no global syscon\n");
+ return PTR_ERR(map);
+ }
+
+ /* Set up the SATA bridge if need be */
+ if (of_property_read_bool(np, "cortina,gemini-enable-sata-bridge")) {
+ ret = gemini_sata_bridge_init(sg);
+ if (ret)
+ return ret;
+ }
+
+ if (of_property_read_bool(np, "cortina,gemini-enable-ide-pins"))
+ sg->ide_pins = true;
+
+ if (!sg->sata_bridge && !sg->ide_pins) {
+ dev_err(dev, "neither SATA bridge or IDE output enabled\n");
+ ret = -EINVAL;
+ goto out_unprep_clk;
+ }
+
+ ret = of_property_read_u32(np, "cortina,gemini-ata-muxmode", &muxmode);
+ if (ret) {
+ dev_err(dev, "could not parse ATA muxmode\n");
+ goto out_unprep_clk;
+ }
+ if (muxmode > GEMINI_MUXMODE_3) {
+ dev_err(dev, "illegal muxmode %d\n", muxmode);
+ ret = -EINVAL;
+ goto out_unprep_clk;
+ }
+ sg->muxmode = muxmode;
+ gmask = GEMINI_IDE_IOMUX_MASK;
+ gmode = (muxmode << GEMINI_IDE_IOMUX_SHIFT);
+
+ /*
+ * If we mux out the IDE, parallel flash must be disabled.
+ * SATA0 and SATA1 have dedicated pins and may coexist with
+ * parallel flash.
+ */
+ if (sg->ide_pins)
+ gmode |= GEMINI_IDE_PADS_ENABLE | GEMINI_PFLASH_PADS_DISABLE;
+ else
+ gmask |= GEMINI_IDE_PADS_ENABLE;
+
+ ret = regmap_update_bits(map, GEMINI_GLOBAL_MISC_CTRL, gmask, gmode);
+ if (ret) {
+ dev_err(dev, "unable to set up IDE muxing\n");
+ ret = -ENODEV;
+ goto out_unprep_clk;
+ }
+
+ /* FIXME: add more elaborate IDE skew control handling */
+ if (sg->ide_pins) {
+ ret = regmap_read(map, GEMINI_GLOBAL_IDE_SKEW_CTRL, &val);
+ if (ret) {
+ dev_err(dev, "cannot read IDE skew control register\n");
+ return ret;
+ }
+ dev_info(dev, "IDE skew control: %08x\n", val);
+ }
+
+ dev_info(dev, "set up the Gemini IDE/SATA nexus\n");
+ platform_set_drvdata(pdev, sg);
+ sg_singleton = sg;
+
+ return 0;
+
+out_unprep_clk:
+ if (sg->sata_bridge) {
+ clk_unprepare(sg->sata1_pclk);
+ clk_unprepare(sg->sata0_pclk);
+ }
+ return ret;
+}
+
+static int gemini_sata_remove(struct platform_device *pdev)
+{
+ struct sata_gemini *sg = platform_get_drvdata(pdev);
+
+ if (sg->sata_bridge) {
+ clk_unprepare(sg->sata1_pclk);
+ clk_unprepare(sg->sata0_pclk);
+ }
+ sg_singleton = NULL;
+
+ return 0;
+}
+
+static const struct of_device_id gemini_sata_of_match[] = {
+ {
+ .compatible = "cortina,gemini-sata-bridge",
+ },
+ {},
+};
+
+static struct platform_driver gemini_sata_driver = {
+ .driver = {
+ .name = DRV_NAME,
+ .of_match_table = of_match_ptr(gemini_sata_of_match),
+ },
+ .probe = gemini_sata_probe,
+ .remove = gemini_sata_remove,
+};
+module_platform_driver(gemini_sata_driver);
+
+MODULE_AUTHOR("Linus Walleij <linus.walleij@linaro.org>");
+MODULE_LICENSE("GPL");
+MODULE_ALIAS("platform:" DRV_NAME);
diff --git a/drivers/ata/sata_gemini.h b/drivers/ata/sata_gemini.h
new file mode 100644
index 000000000000..ca1837a394c8
--- /dev/null
+++ b/drivers/ata/sata_gemini.h
@@ -0,0 +1,21 @@
+/* Header for the Gemini SATA bridge */
+#ifndef SATA_GEMINI_H
+#define SATA_GEMINI_H
+
+struct sata_gemini;
+
+enum gemini_muxmode {
+ GEMINI_MUXMODE_0 = 0,
+ GEMINI_MUXMODE_1,
+ GEMINI_MUXMODE_2,
+ GEMINI_MUXMODE_3,
+};
+
+struct sata_gemini *gemini_sata_bridge_get(void);
+bool gemini_sata_bridge_enabled(struct sata_gemini *sg, bool is_ata1);
+enum gemini_muxmode gemini_sata_get_muxmode(struct sata_gemini *sg);
+int gemini_sata_start_bridge(struct sata_gemini *sg, unsigned int bridge);
+void gemini_sata_stop_bridge(struct sata_gemini *sg, unsigned int bridge);
+int gemini_sata_reset_bridge(struct sata_gemini *sg, unsigned int bridge);
+
+#endif
--
2.9.4
^ permalink raw reply related
* [PATCH 2/4 v4] ata: Add DT bindings for the Gemini SATA bridge
From: Linus Walleij @ 2017-06-04 8:50 UTC (permalink / raw)
To: Tejun Heo, Bartlomiej Zolnierkiewicz, linux-ide
Cc: Janos Laube, Paulius Zaleckas, linux-arm-kernel, Hans Ulli Kroll,
Florian Fainelli, Linus Walleij, devicetree,
John Feng-Hsin Chiang, Greentime Hu
In-Reply-To: <20170604085009.11902-1-linus.walleij@linaro.org>
This adds device tree bindings for the Cortina Systems Gemini
PATA to SATA bridge.
Cc: devicetree@vger.kernel.org
Cc: John Feng-Hsin Chiang <john453@faraday-tech.com>
Cc: Greentime Hu <green.hu@gmail.com>
Acked-by: Hans Ulli Kroll <ulli.kroll@googlemail.com>
Acked-by: Rob Herring <robh@kernel.org>
Signed-off-by: Linus Walleij <linus.walleij@linaro.org>
---
ChangeLog v3->v4:
- No changes, just resending to keep the patch set together.
ChangeLog v2->v3:
- No changes, just resending to keep the patch set together.
ChangeLog v1->v2:
- Fix ata0 misspelled as ata1 in one place.
---
.../bindings/ata/cortina,gemini-sata-bridge.txt | 55 ++++++++++++++++++++++
1 file changed, 55 insertions(+)
create mode 100644 Documentation/devicetree/bindings/ata/cortina,gemini-sata-bridge.txt
diff --git a/Documentation/devicetree/bindings/ata/cortina,gemini-sata-bridge.txt b/Documentation/devicetree/bindings/ata/cortina,gemini-sata-bridge.txt
new file mode 100644
index 000000000000..1c3d3cc70051
--- /dev/null
+++ b/Documentation/devicetree/bindings/ata/cortina,gemini-sata-bridge.txt
@@ -0,0 +1,55 @@
+* Cortina Systems Gemini SATA Bridge
+
+The Gemini SATA bridge in a SoC-internal PATA to SATA bridge that
+takes two Faraday Technology FTIDE010 PATA controllers and bridges
+them in different configurations to two SATA ports.
+
+Required properties:
+- compatible: should be
+ "cortina,gemini-sata-bridge"
+- reg: registers and size for the block
+- resets: phandles to the reset lines for both SATA bridges
+- reset-names: must be "sata0", "sata1"
+- clocks: phandles to the compulsory peripheral clocks
+- clock-names: must be "SATA0_PCLK", "SATA1_PCLK"
+- syscon: a phandle to the global Gemini system controller
+- cortina,gemini-ata-muxmode: tell the desired multiplexing mode for
+ the ATA controller and SATA bridges. Values 0..3:
+ Mode 0: ata0 master <-> sata0
+ ata1 master <-> sata1
+ ata0 slave interface brought out on IDE pads
+ Mode 1: ata0 master <-> sata0
+ ata1 master <-> sata1
+ ata1 slave interface brought out on IDE pads
+ Mode 2: ata1 master <-> sata1
+ ata1 slave <-> sata0
+ ata0 master and slave interfaces brought out
+ on IDE pads
+ Mode 3: ata0 master <-> sata0
+ ata0 slave <-> sata1
+ ata1 master and slave interfaces brought out
+ on IDE pads
+
+Optional boolean properties:
+- cortina,gemini-enable-ide-pins: enables the PATA to IDE connection.
+ The muxmode setting decides whether ATA0 or ATA1 is brought out,
+ and whether master, slave or both interfaces get brought out.
+- cortina,gemini-enable-sata-bridge: enables the PATA to SATA bridge
+ inside the Gemnini SoC. The Muxmode decides what PATA blocks will
+ be muxed out and how.
+
+Example:
+
+sata: sata@46000000 {
+ compatible = "cortina,gemini-sata-bridge";
+ reg = <0x46000000 0x100>;
+ resets = <&rcon 26>, <&rcon 27>;
+ reset-names = "sata0", "sata1";
+ clocks = <&gcc GEMINI_CLK_GATE_SATA0>,
+ <&gcc GEMINI_CLK_GATE_SATA1>;
+ clock-names = "SATA0_PCLK", "SATA1_PCLK";
+ syscon = <&syscon>;
+ cortina,gemini-ata-muxmode = <3>;
+ cortina,gemini-enable-ide-pins;
+ cortina,gemini-enable-sata-bridge;
+};
--
2.9.4
^ permalink raw reply related
* [PATCH 1/4 v4] ata: Add DT bindings for Faraday Technology FTIDE010
From: Linus Walleij @ 2017-06-04 8:50 UTC (permalink / raw)
To: Tejun Heo, Bartlomiej Zolnierkiewicz, linux-ide
Cc: Janos Laube, Paulius Zaleckas, linux-arm-kernel, Hans Ulli Kroll,
Florian Fainelli, Linus Walleij, devicetree,
John Feng-Hsin Chiang, Greentime Hu
This adds device tree bindings for the Faraday Technology
FTIDE010 found in the Storlink/Storm/Cortina Systems Gemini SoC.
I am not 100% sure that this part is from Faraday Technology but
a lot points in that direction:
- A later IDE interface called FTIDE020 exist and share some
properties.
- The SATA bridge has the same Built In Self Test (BIST) that the
Faraday FTSATA100 seems to have, and it has version number 0100
in the device ID register, so this is very likely a FTSATA100
bundled with the FTIDE010.
Cc: devicetree@vger.kernel.org
Cc: John Feng-Hsin Chiang <john453@faraday-tech.com>
Cc: Greentime Hu <green.hu@gmail.com>
Acked-by: Hans Ulli Kroll <ulli.kroll@googlemail.com>
Acked-by: Rob Herring <robh@kernel.org>
Signed-off-by: Linus Walleij <linus.walleij@linaro.org>
---
ChangeLog v3->v4:
- No changes, just resending to keep the patch set together.
ChangeLog v2->v3:
- No changes, just resending to keep the patch set together.
ChangeLog v1->v2:
- Cut the timings defintions from the device tree. Hard-code
it in the driver instead, keeping the nice layout and
configurability by making it easy to tweak the timings
in the code.
- Fix up some confused references to 50 MHz in 66 MHz
properties.
---
.../devicetree/bindings/ata/faraday,ftide010.txt | 38 ++++++++++++++++++++++
1 file changed, 38 insertions(+)
create mode 100644 Documentation/devicetree/bindings/ata/faraday,ftide010.txt
diff --git a/Documentation/devicetree/bindings/ata/faraday,ftide010.txt b/Documentation/devicetree/bindings/ata/faraday,ftide010.txt
new file mode 100644
index 000000000000..a0c64a29104d
--- /dev/null
+++ b/Documentation/devicetree/bindings/ata/faraday,ftide010.txt
@@ -0,0 +1,38 @@
+* Faraday Technology FTIDE010 PATA controller
+
+This controller is the first Faraday IDE interface block, used in the
+StorLink SL2312 and SL3516, later known as the Cortina Systems Gemini
+platform. The controller can do PIO modes 0 through 4, Multi-word DMA
+(MWDM)modes 0 through 2 and Ultra DMA modes 0 through 6.
+
+On the Gemini platform, this PATA block is accompanied by a PATA to
+SATA bridge in order to support SATA. This is why a phandle to that
+controller is compulsory on that platform.
+
+The timing properties are unique per-SoC, not per-board.
+
+Required properties:
+- compatible: should be one of
+ "cortina,gemini-pata", "faraday,ftide010"
+ "faraday,ftide010"
+- interrupts: interrupt for the block
+- reg: registers and size for the block
+
+Optional properties:
+- clocks: a SoC clock running the peripheral.
+- clock-names: should be set to "PCLK" for the peripheral clock.
+
+Required properties for "cortina,gemini-pata" compatible:
+- sata: a phande to the Gemini PATA to SATA bridge, see
+ cortina,gemini-sata-bridge.txt for details.
+
+Example:
+
+ata@63000000 {
+ compatible = "cortina,gemini-pata", "faraday,ftide010";
+ reg = <0x63000000 0x100>;
+ interrupts = <4 IRQ_TYPE_EDGE_RISING>;
+ clocks = <&gcc GEMINI_CLK_GATE_IDE>;
+ clock-names = "PCLK";
+ sata = <&sata>;
+};
--
2.9.4
^ permalink raw reply related
* Re: [PATCH 3/4 v3] ata: Add driver for Faraday Technology FTIDE010
From: Linus Walleij @ 2017-06-04 8:39 UTC (permalink / raw)
To: Bartlomiej Zolnierkiewicz
Cc: Tejun Heo, linux-ide, Janos Laube, Paulius Zaleckas,
linux-arm-kernel@lists.infradead.org, Hans Ulli Kroll,
Florian Fainelli, John Feng-Hsin Chiang, Greentime Hu
In-Reply-To: <1937268.BD9NpZS46X@amdc3058>
Hi Barlomiej,
thanks a *lot* for detailed review and for showing me some really
tricky corners of ATA support!
Most things I just fixed, will send v4 soon.
On Tue, May 30, 2017 at 4:31 PM, Bartlomiej Zolnierkiewicz
<b.zolnierkie@samsung.com> wrote:
>> +static const bool set_mdma_66_mhz[] = { true, true, true, true };
>
> 50 MHz MWDMA timings are never used by the driver and can be removed..
I think it's nice to keep around as documentation really, and someone may want
to patch it in and experiment with 50MHz mode if things are not
working for them.
> CLK_MOD_REG is shared between master and slave so the driver needs to
> make sure that right clock is used if master and slave devices require
> different clocks (i.e. master is using UDMA5 and slave is using UDMA6).
(...)
> Moreover MWDMA_TIMING_REG is also shared between devices.
(...)
> ->qc_issue method can be used to program the right tuning values, i.e.
Wow thanks a lot for clearing this up!
I was a bit confused about how to deal with this. Now it makes a
lot more sense!
> static unsigned int ftide010_qc_issue(struct ata_queued_cmd *qc)
> {
> struct ata_port *ap = qc->ap;
> struct ata_device *adev = qc->dev;
>
> if (adev != ap->private_data && ata_dma_enabled(adev))
> ftide010_set_dmamode(ap, adev);
>
> return ata_bmdma_qc_issue(qc);
> }
>
> [ set ap->private_data to adev at the end of ftide010_set_dmamode() ]
I implemented this exactly as above, with some extra comments
so it's clear what is going on.
>> +static int pata_ftide010_gemini_cable_detect(struct ata_port *ap)
>> +{
>> + struct ftide010 *ftide = ap->host->private_data;
>> +
>> + /*
>> + * Return the master cable, I have no clue how to return a different
>> + * cable for the slave than for the master.
>> + */
>
> Seems like ->cable_detect needs to operate on ata_device * now?
>
> Tejun?
Yeah... it looks like something libata is not really made to handle.
This platform has one IRQ for each port bridge anyways.
>> + case GEMINI_MUXMODE_3:
>> + ftide->master_cbl = ATA_CBL_PATA40;
>> + ftide->slave_cbl = ATA_CBL_PATA40;
>> + break;
>> + }
>
> It seems that for PATA devices 80-wires cable will be never
> used, is this correct?
That is a simplification. I haven't seen any systems using the
PATA interface at all.
I have put in some comments that we assume the
40-wire interface, and if something else like 80-wire is in use
then that needs to be specified in the device tree since the
SoC and driver cannot detect it without special hardware.
I guess I could add DT properties for it but it seems a bit
speculative since I can't test it.
Yours,
Linus Walleij
^ permalink raw reply
* Investment Interest & Offer
From: Seydou Thieba @ 2017-06-02 23:01 UTC (permalink / raw)
To: Recipients
^ permalink raw reply
* Re: [PATCH] ahci: qoriq: add ls1088a platforms support
From: Tejun Heo @ 2017-06-02 13:50 UTC (permalink / raw)
To: Yuantian Tang; +Cc: linux-ide, linux-kernel, linux-arm-kernel
In-Reply-To: <1496388183-11534-1-git-send-email-andy.tang@nxp.com>
On Fri, Jun 02, 2017 at 03:23:03PM +0800, Yuantian Tang wrote:
> Ls1088a is new introduced arm-based soc with sata support with
> following features:
>
> * Complies with the serial ATA 3.0 specification
> and the AHCI 1.3.1 specification
> * Contains a high-speed descriptor-based DMA controller
> * Supports the following:
> * Speeds of 1.5 Gb/s (first-generation SATA),
> 3 Gb/s (second-generation SATA), and 6 Gb/s (third-generation SATA)
> * FIS-based switching
> * Native command queuing (NCQ) commands
> * Port multiplier operation
> * Asynchronous notification
> * SATA Vendor BIST mode
>
> Signed-off-by: Tang Yuantian <andy.tang@nxp.com>
Applied to libata/for-4.13.
Thanks.
--
tejun
^ permalink raw reply
* [PATCH V4 3/3] dt-bindings: tegra: add binding documentation
From: Preetham Chandru Ramchandra @ 2017-06-02 12:53 UTC (permalink / raw)
To: thierry.reding-Re5JQEeQqe8AvxtiuMwx3w, tj-DgEjT+Ai2ygdnm+yROfE0A,
cyndis-/1wQRMveznE
Cc: preetham260-Re5JQEeQqe8AvxtiuMwx3w,
linux-tegra-u79uwXL29TY76Z2rM5mHXA,
linux-ide-u79uwXL29TY76Z2rM5mHXA,
vbyravarasu-DDmLM1+adcrQT0dZR+AlfA,
pkunapuli-DDmLM1+adcrQT0dZR+AlfA, Preetham Chandru R
In-Reply-To: <1496408000-24856-1-git-send-email-pchandru-DDmLM1+adcrQT0dZR+AlfA@public.gmane.org>
From: Preetham Chandru R <pchandru-DDmLM1+adcrQT0dZR+AlfA@public.gmane.org>
This adds bindings documentation for the
AHCI controller on Tegra210
Signed-off-by: Preetham Chandru R <pchandru-DDmLM1+adcrQT0dZR+AlfA@public.gmane.org>
---
v4:
* changed the commit message
* changed 'sata-cold' reset to mandatory for t210 and t124
* Removed the regulators for T210 since these regulators
will be enabled in phy driver.
v3:
* Add AUX register.
v2:
* change cml1, pll_e and phy regulators as optional
for T210.
---
.../bindings/ata/nvidia,tegra124-ahci.txt | 38 ++++++++++++++--------
1 file changed, 25 insertions(+), 13 deletions(-)
diff --git a/Documentation/devicetree/bindings/ata/nvidia,tegra124-ahci.txt b/Documentation/devicetree/bindings/ata/nvidia,tegra124-ahci.txt
index 66c83c3..df4dc2c 100644
--- a/Documentation/devicetree/bindings/ata/nvidia,tegra124-ahci.txt
+++ b/Documentation/devicetree/bindings/ata/nvidia,tegra124-ahci.txt
@@ -1,20 +1,19 @@
-Tegra124 SoC SATA AHCI controller
+Tegra SoC SATA AHCI controller
Required properties :
-- compatible : For Tegra124, must contain "nvidia,tegra124-ahci". Otherwise,
- must contain '"nvidia,<chip>-ahci", "nvidia,tegra124-ahci"', where <chip>
- is tegra132.
-- reg : Should contain 2 entries:
+- compatible : Must be one of:
+ - Tegra124 : "nvidia,tegra124-ahci"
+ - Tegra210 : "nvidia,tegra210-ahci"
+- reg : Should contain 3 entries:
- AHCI register set (SATA BAR5)
- SATA register set
+ - Tegra210 : AUX register set
- interrupts : Defines the interrupt used by SATA
- clocks : Must contain an entry for each entry in clock-names.
See ../clocks/clock-bindings.txt for details.
- clock-names : Must include the following entries:
- sata
- sata-oob
- - cml1
- - pll_e
- resets : Must contain an entry for each entry in reset-names.
See ../reset/reset.txt for details.
- reset-names : Must include the following entries:
@@ -24,9 +23,22 @@ Required properties :
- phys : Must contain an entry for each entry in phy-names.
See ../phy/phy-bindings.txt for details.
- phy-names : Must include the following entries:
- - sata-phy : XUSB PADCTL SATA PHY
-- hvdd-supply : Defines the SATA HVDD regulator
-- vddio-supply : Defines the SATA VDDIO regulator
-- avdd-supply : Defines the SATA AVDD regulator
-- target-5v-supply : Defines the SATA 5V power regulator
-- target-12v-supply : Defines the SATA 12V power regulator
+ - For T124:
+ - sata-phy : XUSB PADCTL SATA PHY
+ - For T210:
+ - sata-0
+- For T124:
+ - hvdd-supply : Defines the SATA HVDD regulator
+ - vddio-supply : Defines the SATA VDDIO regulator
+ - avdd-supply : Defines the SATA AVDD regulator
+ - target-5v-supply : Defines the SATA 5V power regulator
+ - target-12v-supply : Defines the SATA 12V power regulator
+
+Optional properties:
+- clock-names :
+ - cml1 :
+ cml1 clock is required by phy so it is optional to define
+ here as phy driver will be enabling this clock.
+ - pll_e :
+ pll_e is the parent of cml1 clock so it is optional to define
+ here as phy driver will be enabling this clock.
--
2.1.4
^ permalink raw reply related
* [PATCH V4 2/3] arm64: tegra: Enable AHCI on Tegra210
From: Preetham Chandru Ramchandra @ 2017-06-02 12:53 UTC (permalink / raw)
To: thierry.reding-Re5JQEeQqe8AvxtiuMwx3w, tj-DgEjT+Ai2ygdnm+yROfE0A,
cyndis-/1wQRMveznE
Cc: preetham260-Re5JQEeQqe8AvxtiuMwx3w,
linux-tegra-u79uwXL29TY76Z2rM5mHXA,
linux-ide-u79uwXL29TY76Z2rM5mHXA,
vbyravarasu-DDmLM1+adcrQT0dZR+AlfA,
pkunapuli-DDmLM1+adcrQT0dZR+AlfA, Preetham Chandru R
In-Reply-To: <1496408000-24856-1-git-send-email-pchandru-DDmLM1+adcrQT0dZR+AlfA@public.gmane.org>
From: Preetham Chandru R <pchandru-DDmLM1+adcrQT0dZR+AlfA@public.gmane.org>
Enable AHCI on Tegra210 systems.
Signed-off-by: Preetham Chandru R <pchandru-DDmLM1+adcrQT0dZR+AlfA@public.gmane.org>
---
v4:
* Fixed missing space after 'AUX'
---
arch/arm64/boot/dts/nvidia/tegra210-p2597.dtsi | 6 ++++++
arch/arm64/boot/dts/nvidia/tegra210.dtsi | 16 ++++++++++++++++
2 files changed, 22 insertions(+)
diff --git a/arch/arm64/boot/dts/nvidia/tegra210-p2597.dtsi b/arch/arm64/boot/dts/nvidia/tegra210-p2597.dtsi
index e5fc67b..58c28b9 100644
--- a/arch/arm64/boot/dts/nvidia/tegra210-p2597.dtsi
+++ b/arch/arm64/boot/dts/nvidia/tegra210-p2597.dtsi
@@ -1324,6 +1324,12 @@
status = "okay";
};
+ sata@70020000 {
+ status = "okay";
+ phys = <&{/padctl@7009f000/pads/sata/lanes/sata-0}>;
+ phy-names = "sata-0";
+ };
+
padctl@7009f000 {
status = "okay";
diff --git a/arch/arm64/boot/dts/nvidia/tegra210.dtsi b/arch/arm64/boot/dts/nvidia/tegra210.dtsi
index 8f26c4d..2de5bee 100644
--- a/arch/arm64/boot/dts/nvidia/tegra210.dtsi
+++ b/arch/arm64/boot/dts/nvidia/tegra210.dtsi
@@ -795,6 +795,22 @@
#iommu-cells = <1>;
};
+ sata@70020000 {
+ compatible = "nvidia,tegra210-ahci";
+ reg = <0x0 0x70027000 0x0 0x2000>, /* AHCI */
+ <0x0 0x70020000 0x0 0x7000>, /* SATA */
+ <0x0 0x70001100 0x0 0x1000>; /* SATA AUX */
+ interrupts = <GIC_SPI 23 IRQ_TYPE_LEVEL_HIGH>;
+ clocks = <&tegra_car TEGRA210_CLK_SATA>,
+ <&tegra_car TEGRA210_CLK_SATA_OOB>;
+ clock-names = "sata", "sata-oob";
+ resets = <&tegra_car 124>,
+ <&tegra_car 123>,
+ <&tegra_car 129>;
+ reset-names = "sata", "sata-oob", "sata-cold";
+ status = "disabled";
+ };
+
hda@70030000 {
compatible = "nvidia,tegra210-hda", "nvidia,tegra30-hda";
reg = <0x0 0x70030000 0x0 0x10000>;
--
2.1.4
^ permalink raw reply related
* [PATCH V4 1/3] ata: ahci_tegra: Add AHCI support for tegra210
From: Preetham Chandru Ramchandra @ 2017-06-02 12:53 UTC (permalink / raw)
To: thierry.reding-Re5JQEeQqe8AvxtiuMwx3w, tj-DgEjT+Ai2ygdnm+yROfE0A,
cyndis-/1wQRMveznE
Cc: preetham260-Re5JQEeQqe8AvxtiuMwx3w,
linux-tegra-u79uwXL29TY76Z2rM5mHXA,
linux-ide-u79uwXL29TY76Z2rM5mHXA,
vbyravarasu-DDmLM1+adcrQT0dZR+AlfA,
pkunapuli-DDmLM1+adcrQT0dZR+AlfA, Preetham Chandru R
In-Reply-To: <1496408000-24856-1-git-send-email-pchandru-DDmLM1+adcrQT0dZR+AlfA@public.gmane.org>
From: Preetham Chandru R <pchandru-DDmLM1+adcrQT0dZR+AlfA@public.gmane.org>
1. Move tegra124 specifics to tegra124_ahci_init.
2. Separate the regulators needed for tegra124 and tegra210.
3. Disable DIPM for t210 and t124 as there are known issues.
4. Disable Devslp for t210 since devslp pin is shared with
pcie clkreq.
Signed-off-by: Preetham Chandru R <pchandru-DDmLM1+adcrQT0dZR+AlfA@public.gmane.org>
---
v4:
* Instead of disabling DIPM through quirk function,
hardcode by adding ATA_FLAG_NO_DIPM to
ahci_tegra_port_info's static definition
* Changed access to aux register to optional because for T124,
we need to continue to support older device trees without
the aux_regs property
v3:
* Remove inline functions for read/write and modify to
SATA, SATA Config and SATA Aux registers.
* Add code to disable DIPM and DevSlp for t210 and t124
v2:
* Fix indentation issues
* Move the change to disable DIPM, HIPM, DevSlp, partial,
slumber and NCQ into a separate patch
---
drivers/ata/ahci_tegra.c | 386 ++++++++++++++++++++++++++++++++++++-----------
1 file changed, 302 insertions(+), 84 deletions(-)
diff --git a/drivers/ata/ahci_tegra.c b/drivers/ata/ahci_tegra.c
index 3a62eb2..75520e5 100644
--- a/drivers/ata/ahci_tegra.c
+++ b/drivers/ata/ahci_tegra.c
@@ -34,7 +34,8 @@
#define DRV_NAME "tegra-ahci"
#define SATA_CONFIGURATION_0 0x180
-#define SATA_CONFIGURATION_EN_FPCI BIT(0)
+#define SATA_CONFIGURATION_0_EN_FPCI BIT(0)
+#define SATA_CONFIGURATION_0_CLK_OVERRIDE BIT(31)
#define SCFG_OFFSET 0x1000
@@ -45,17 +46,55 @@
#define T_SATA0_CFG_1_SERR BIT(8)
#define T_SATA0_CFG_9 0x24
-#define T_SATA0_CFG_9_BASE_ADDRESS_SHIFT 13
+#define T_SATA0_CFG_9_BASE_ADDRESS 0x40020000
#define SATA_FPCI_BAR5 0x94
-#define SATA_FPCI_BAR5_START_SHIFT 4
+#define SATA_FPCI_BAR5_START_MASK (0xfffffff << 4)
+#define SATA_FPCI_BAR5_START (0x0040020 << 4)
+#define SATA_FPCI_BAR5_ACCESS_TYPE (0x1)
#define SATA_INTR_MASK 0x188
#define SATA_INTR_MASK_IP_INT_MASK BIT(16)
+#define T_SATA0_CFG_35 0x94
+#define T_SATA0_CFG_35_IDP_INDEX_MASK (0x7ff << 2)
+#define T_SATA0_CFG_35_IDP_INDEX (0x2a << 2)
+
+#define T_SATA0_AHCI_IDP1 0x98
+#define T_SATA0_AHCI_IDP1_DATA (0x400040)
+
+#define T_SATA0_CFG_PHY_1 0x12c
+#define T_SATA0_CFG_PHY_1_PADS_IDDQ_EN BIT(23)
+#define T_SATA0_CFG_PHY_1_PAD_PLL_IDDQ_EN BIT(22)
+
+#define T_SATA0_NVOOB 0x114
+#define T_SATA0_NVOOB_COMMA_CNT_MASK (0xff << 16)
+#define T_SATA0_NVOOB_COMMA_CNT (0x07 << 16)
+#define T_SATA0_NVOOB_SQUELCH_FILTER_MODE_MASK (0x3 << 24)
+#define T_SATA0_NVOOB_SQUELCH_FILTER_MODE (0x1 << 24)
+#define T_SATA0_NVOOB_SQUELCH_FILTER_LENGTH_MASK (0x3 << 26)
+#define T_SATA0_NVOOB_SQUELCH_FILTER_LENGTH (0x3 << 26)
+
+#define T_SATA_CFG_PHY_0 0x120
+#define T_SATA_CFG_PHY_0_USE_7BIT_ALIGN_DET_FOR_SPD BIT(11)
+#define T_SATA_CFG_PHY_0_MASK_SQUELCH BIT(24)
+
+#define T_SATA0_CFG2NVOOB_2 0x134
+#define T_SATA0_CFG2NVOOB_2_COMWAKE_IDLE_CNT_LOW_MASK (0x1ff << 18)
+#define T_SATA0_CFG2NVOOB_2_COMWAKE_IDLE_CNT_LOW (0xc << 18)
+
#define T_SATA0_AHCI_HBA_CAP_BKDR 0x300
+#define T_SATA0_AHCI_HBA_CAP_BKDR_PARTIAL_ST_CAP BIT(13)
+#define T_SATA0_AHCI_HBA_CAP_BKDR_SLUMBER_ST_CAP BIT(14)
+#define T_SATA0_AHCI_HBA_CAP_BKDR_SALP BIT(26)
+#define T_SATA0_AHCI_HBA_CAP_BKDR_SUPP_PM BIT(17)
+#define T_SATA0_AHCI_HBA_CAP_BKDR_SNCQ BIT(30)
#define T_SATA0_BKDOOR_CC 0x4a4
+#define T_SATA0_BKDOOR_CC_CLASS_CODE_MASK (0xffff << 16)
+#define T_SATA0_BKDOOR_CC_CLASS_CODE (0x0106 << 16)
+#define T_SATA0_BKDOOR_CC_PROG_IF_MASK (0xff << 8)
+#define T_SATA0_BKDOOR_CC_PROG_IF (0x01 << 8)
#define T_SATA0_CFG_SATA 0x54c
#define T_SATA0_CFG_SATA_BACKDOOR_PROG_IF_EN BIT(12)
@@ -82,9 +121,35 @@
#define T_SATA0_CHX_PHY_CTRL11 0x6d0
#define T_SATA0_CHX_PHY_CTRL11_GEN2_RX_EQ (0x2800 << 16)
+#define T_SATA0_CHX_PHY_CTRL17_0 0x6e8
+#define T_SATA0_CHX_PHY_CTRL17_0_RX_EQ_CTRL_L_GEN1 0x55010000
+#define T_SATA0_CHX_PHY_CTRL18_0 0x6ec
+#define T_SATA0_CHX_PHY_CTRL18_0_RX_EQ_CTRL_L_GEN2 0x55010000
+#define T_SATA0_CHX_PHY_CTRL20_0 0x6f4
+#define T_SATA0_CHX_PHY_CTRL20_0_RX_EQ_CTRL_H_GEN1 0x1
+#define T_SATA0_CHX_PHY_CTRL21_0 0x6f8
+#define T_SATA0_CHX_PHY_CTRL21_0_RX_EQ_CTRL_H_GEN2 0x1
+
+/* AUX Registers */
+#define SATA_AUX_MISC_CNTL_1_0 0x8
+#define SATA_AUX_MISC_CNTL_1_0_DEVSLP_OVERRIDE BIT(17)
+#define SATA_AUX_MISC_CNTL_1_0_SDS_SUPPORT BIT(13)
+#define SATA_AUX_MISC_CNTL_1_0_DESO_SUPPORT BIT(15)
+
+#define SATA_AUX_RX_STAT_INT_0 0xc
+#define SATA_AUX_RX_STAT_INT_0_SATA_DEVSLP BIT(7)
+
+#define SATA_AUX_SPARE_CFG0_0 0x18
+#define SATA_AUX_SPARE_CFG0_0_MDAT_TIMER_AFTER_PG_VALID BIT(14)
+
#define FUSE_SATA_CALIB 0x124
#define FUSE_SATA_CALIB_MASK 0x3
+enum {
+ NO_DEVSLP = (1 << 0),
+ NO_DIPM = (1 << 1),
+};
+
struct sata_pad_calibration {
u8 gen1_tx_amp;
u8 gen1_tx_peak;
@@ -99,15 +164,91 @@ static const struct sata_pad_calibration tegra124_pad_calibration[] = {
{0x14, 0x0e, 0x1a, 0x0e},
};
+struct tegra_ahci_ops {
+ int (*init)(struct ahci_host_priv *);
+};
+
+struct tegra_ahci_soc {
+ const char *const *supply_names;
+ u32 num_supplies;
+ u32 quirks;
+ struct tegra_ahci_ops ops;
+};
+
struct tegra_ahci_priv {
struct platform_device *pdev;
void __iomem *sata_regs;
+ void __iomem *sata_aux_regs;
struct reset_control *sata_rst;
struct reset_control *sata_oob_rst;
struct reset_control *sata_cold_rst;
/* Needs special handling, cannot use ahci_platform */
struct clk *sata_clk;
- struct regulator_bulk_data supplies[5];
+ struct regulator_bulk_data *supplies;
+ struct tegra_ahci_soc *soc_data;
+};
+
+static const char *const tegra124_supply_names[] = {
+ "avdd", "hvdd", "vddio", "target-5v", "target-12v"
+};
+
+static void tegra_ahci_handle_quirks(struct ahci_host_priv *hpriv);
+
+static int tegra124_ahci_init(struct ahci_host_priv *hpriv)
+{
+ struct tegra_ahci_priv *tegra = hpriv->plat_data;
+ struct sata_pad_calibration calib;
+ int ret;
+ u32 val;
+
+ /* Pad calibration */
+ ret = tegra_fuse_readl(FUSE_SATA_CALIB, &val);
+ if (ret)
+ return ret;
+
+ calib = tegra124_pad_calibration[val & FUSE_SATA_CALIB_MASK];
+
+ writel(BIT(0), tegra->sata_regs + SCFG_OFFSET + T_SATA0_INDEX);
+
+ val = readl(tegra->sata_regs +
+ SCFG_OFFSET + T_SATA0_CHX_PHY_CTRL1_GEN1);
+ val &= ~T_SATA0_CHX_PHY_CTRL1_GEN1_TX_AMP_MASK;
+ val &= ~T_SATA0_CHX_PHY_CTRL1_GEN1_TX_PEAK_MASK;
+ val |= calib.gen1_tx_amp << T_SATA0_CHX_PHY_CTRL1_GEN1_TX_AMP_SHIFT;
+ val |= calib.gen1_tx_peak << T_SATA0_CHX_PHY_CTRL1_GEN1_TX_PEAK_SHIFT;
+ writel(val, tegra->sata_regs + SCFG_OFFSET +
+ T_SATA0_CHX_PHY_CTRL1_GEN1);
+
+ val = readl(tegra->sata_regs +
+ SCFG_OFFSET + T_SATA0_CHX_PHY_CTRL1_GEN2);
+ val &= ~T_SATA0_CHX_PHY_CTRL1_GEN2_TX_AMP_MASK;
+ val &= ~T_SATA0_CHX_PHY_CTRL1_GEN2_TX_PEAK_MASK;
+ val |= calib.gen2_tx_amp << T_SATA0_CHX_PHY_CTRL1_GEN1_TX_AMP_SHIFT;
+ val |= calib.gen2_tx_peak << T_SATA0_CHX_PHY_CTRL1_GEN1_TX_PEAK_SHIFT;
+ writel(val, tegra->sata_regs + SCFG_OFFSET +
+ T_SATA0_CHX_PHY_CTRL1_GEN2);
+
+ writel(T_SATA0_CHX_PHY_CTRL11_GEN2_RX_EQ,
+ tegra->sata_regs + SCFG_OFFSET + T_SATA0_CHX_PHY_CTRL11);
+ writel(T_SATA0_CHX_PHY_CTRL2_CDR_CNTL_GEN1,
+ tegra->sata_regs + SCFG_OFFSET + T_SATA0_CHX_PHY_CTRL2);
+
+ writel(0, tegra->sata_regs + SCFG_OFFSET + T_SATA0_INDEX);
+
+ return 0;
+}
+
+static const struct tegra_ahci_soc tegra124_ahci_soc_data = {
+ .supply_names = tegra124_supply_names,
+ .num_supplies = ARRAY_SIZE(tegra124_supply_names),
+ .quirks = NO_DIPM | NO_DEVSLP,
+ .ops = {
+ .init = tegra124_ahci_init,
+ },
+};
+
+static const struct tegra_ahci_soc tegra210_ahci_soc_data = {
+ .quirks = NO_DIPM | NO_DEVSLP,
};
static int tegra_ahci_power_on(struct ahci_host_priv *hpriv)
@@ -115,7 +256,7 @@ static int tegra_ahci_power_on(struct ahci_host_priv *hpriv)
struct tegra_ahci_priv *tegra = hpriv->plat_data;
int ret;
- ret = regulator_bulk_enable(ARRAY_SIZE(tegra->supplies),
+ ret = regulator_bulk_enable(tegra->soc_data->num_supplies,
tegra->supplies);
if (ret)
return ret;
@@ -144,8 +285,7 @@ static int tegra_ahci_power_on(struct ahci_host_priv *hpriv)
tegra_powergate_power_off(TEGRA_POWERGATE_SATA);
disable_regulators:
- regulator_bulk_disable(ARRAY_SIZE(tegra->supplies), tegra->supplies);
-
+ regulator_bulk_disable(tegra->soc_data->num_supplies, tegra->supplies);
return ret;
}
@@ -162,97 +302,139 @@ static void tegra_ahci_power_off(struct ahci_host_priv *hpriv)
clk_disable_unprepare(tegra->sata_clk);
tegra_powergate_power_off(TEGRA_POWERGATE_SATA);
- regulator_bulk_disable(ARRAY_SIZE(tegra->supplies), tegra->supplies);
+ regulator_bulk_disable(tegra->soc_data->num_supplies, tegra->supplies);
}
static int tegra_ahci_controller_init(struct ahci_host_priv *hpriv)
{
struct tegra_ahci_priv *tegra = hpriv->plat_data;
int ret;
- unsigned int val;
- struct sata_pad_calibration calib;
+ u32 val;
ret = tegra_ahci_power_on(hpriv);
- if (ret) {
- dev_err(&tegra->pdev->dev,
- "failed to power on AHCI controller: %d\n", ret);
+ if (ret)
return ret;
- }
+ /*
+ * Program the following SATA IPFS registers
+ * to allow SW accesses to SATA's MMIO register range.
+ */
+ val = readl(tegra->sata_regs + SATA_FPCI_BAR5);
+ val &= ~(SATA_FPCI_BAR5_START_MASK | SATA_FPCI_BAR5_ACCESS_TYPE);
+ val |= SATA_FPCI_BAR5_START | SATA_FPCI_BAR5_ACCESS_TYPE;
+ writel(val, tegra->sata_regs + SATA_FPCI_BAR5);
+
+ /* Program the following SATA IPFS register to enable the SATA */
val = readl(tegra->sata_regs + SATA_CONFIGURATION_0);
- val |= SATA_CONFIGURATION_EN_FPCI;
+ val |= SATA_CONFIGURATION_0_EN_FPCI;
writel(val, tegra->sata_regs + SATA_CONFIGURATION_0);
- /* Pad calibration */
-
- ret = tegra_fuse_readl(FUSE_SATA_CALIB, &val);
- if (ret) {
- dev_err(&tegra->pdev->dev,
- "failed to read calibration fuse: %d\n", ret);
- return ret;
- }
-
- calib = tegra124_pad_calibration[val & FUSE_SATA_CALIB_MASK];
-
- writel(BIT(0), tegra->sata_regs + SCFG_OFFSET + T_SATA0_INDEX);
-
- val = readl(tegra->sata_regs +
- SCFG_OFFSET + T_SATA0_CHX_PHY_CTRL1_GEN1);
- val &= ~T_SATA0_CHX_PHY_CTRL1_GEN1_TX_AMP_MASK;
- val &= ~T_SATA0_CHX_PHY_CTRL1_GEN1_TX_PEAK_MASK;
- val |= calib.gen1_tx_amp <<
- T_SATA0_CHX_PHY_CTRL1_GEN1_TX_AMP_SHIFT;
- val |= calib.gen1_tx_peak <<
- T_SATA0_CHX_PHY_CTRL1_GEN1_TX_PEAK_SHIFT;
- writel(val, tegra->sata_regs + SCFG_OFFSET +
- T_SATA0_CHX_PHY_CTRL1_GEN1);
-
- val = readl(tegra->sata_regs +
- SCFG_OFFSET + T_SATA0_CHX_PHY_CTRL1_GEN2);
- val &= ~T_SATA0_CHX_PHY_CTRL1_GEN2_TX_AMP_MASK;
- val &= ~T_SATA0_CHX_PHY_CTRL1_GEN2_TX_PEAK_MASK;
- val |= calib.gen2_tx_amp <<
- T_SATA0_CHX_PHY_CTRL1_GEN1_TX_AMP_SHIFT;
- val |= calib.gen2_tx_peak <<
- T_SATA0_CHX_PHY_CTRL1_GEN1_TX_PEAK_SHIFT;
- writel(val, tegra->sata_regs + SCFG_OFFSET +
- T_SATA0_CHX_PHY_CTRL1_GEN2);
-
- writel(T_SATA0_CHX_PHY_CTRL11_GEN2_RX_EQ,
- tegra->sata_regs + SCFG_OFFSET + T_SATA0_CHX_PHY_CTRL11);
- writel(T_SATA0_CHX_PHY_CTRL2_CDR_CNTL_GEN1,
- tegra->sata_regs + SCFG_OFFSET + T_SATA0_CHX_PHY_CTRL2);
-
- writel(0, tegra->sata_regs + SCFG_OFFSET + T_SATA0_INDEX);
-
- /* Program controller device ID */
+ /* Electrical settings for better link stability */
+ val = T_SATA0_CHX_PHY_CTRL17_0_RX_EQ_CTRL_L_GEN1;
+ writel(val, tegra->sata_regs + SCFG_OFFSET + T_SATA0_CHX_PHY_CTRL17_0);
+ val = T_SATA0_CHX_PHY_CTRL18_0_RX_EQ_CTRL_L_GEN2;
+ writel(val, tegra->sata_regs + SCFG_OFFSET + T_SATA0_CHX_PHY_CTRL18_0);
+ val = T_SATA0_CHX_PHY_CTRL20_0_RX_EQ_CTRL_H_GEN1;
+ writel(val, tegra->sata_regs + SCFG_OFFSET + T_SATA0_CHX_PHY_CTRL20_0);
+ val = T_SATA0_CHX_PHY_CTRL21_0_RX_EQ_CTRL_H_GEN2;
+ writel(val, tegra->sata_regs + SCFG_OFFSET + T_SATA0_CHX_PHY_CTRL21_0);
+
+ /* For SQUELCH Filter & Gen3 drive getting detected as Gen1 drive */
+
+ val = readl(tegra->sata_regs + SCFG_OFFSET + T_SATA_CFG_PHY_0);
+ val |= T_SATA_CFG_PHY_0_MASK_SQUELCH;
+ val &= ~T_SATA_CFG_PHY_0_USE_7BIT_ALIGN_DET_FOR_SPD;
+ writel(val, tegra->sata_regs + SCFG_OFFSET + T_SATA_CFG_PHY_0);
+
+ val = readl(tegra->sata_regs + SCFG_OFFSET + T_SATA0_NVOOB);
+ val &= ~(T_SATA0_NVOOB_COMMA_CNT_MASK |
+ T_SATA0_NVOOB_SQUELCH_FILTER_LENGTH_MASK |
+ T_SATA0_NVOOB_SQUELCH_FILTER_MODE_MASK);
+ val |= (T_SATA0_NVOOB_COMMA_CNT |
+ T_SATA0_NVOOB_SQUELCH_FILTER_LENGTH |
+ T_SATA0_NVOOB_SQUELCH_FILTER_MODE);
+ writel(val, tegra->sata_regs + SCFG_OFFSET + T_SATA0_NVOOB);
+
+ /*
+ * Change CFG2NVOOB_2_COMWAKE_IDLE_CNT_LOW from 83.3 ns to 58.8ns
+ */
+ val = readl(tegra->sata_regs + SCFG_OFFSET + T_SATA0_CFG2NVOOB_2);
+ val &= ~T_SATA0_CFG2NVOOB_2_COMWAKE_IDLE_CNT_LOW_MASK;
+ val |= T_SATA0_CFG2NVOOB_2_COMWAKE_IDLE_CNT_LOW;
+ writel(val, tegra->sata_regs + SCFG_OFFSET + T_SATA0_CFG2NVOOB_2);
+
+ if (tegra->soc_data->ops.init)
+ tegra->soc_data->ops.init(hpriv);
+
+ /*
+ * Program the following SATA configuration registers
+ * to initialize SATA
+ */
+ val = readl(tegra->sata_regs + SCFG_OFFSET + T_SATA0_CFG_1);
+ val |= (T_SATA0_CFG_1_IO_SPACE | T_SATA0_CFG_1_MEMORY_SPACE |
+ T_SATA0_CFG_1_BUS_MASTER | T_SATA0_CFG_1_SERR);
+ writel(val, tegra->sata_regs + SCFG_OFFSET + T_SATA0_CFG_1);
+ val = T_SATA0_CFG_9_BASE_ADDRESS;
+ writel(val, tegra->sata_regs + SCFG_OFFSET + T_SATA0_CFG_9);
+ /* Program Class Code and Programming interface for SATA */
val = readl(tegra->sata_regs + SCFG_OFFSET + T_SATA0_CFG_SATA);
val |= T_SATA0_CFG_SATA_BACKDOOR_PROG_IF_EN;
writel(val, tegra->sata_regs + SCFG_OFFSET + T_SATA0_CFG_SATA);
- writel(0x01060100, tegra->sata_regs + SCFG_OFFSET + T_SATA0_BKDOOR_CC);
+ val = readl(tegra->sata_regs + SCFG_OFFSET + T_SATA0_BKDOOR_CC);
+ val &=
+ ~(T_SATA0_BKDOOR_CC_CLASS_CODE_MASK |
+ T_SATA0_BKDOOR_CC_PROG_IF_MASK);
+ val |= T_SATA0_BKDOOR_CC_CLASS_CODE | T_SATA0_BKDOOR_CC_PROG_IF;
+ writel(val, tegra->sata_regs + SCFG_OFFSET + T_SATA0_BKDOOR_CC);
val = readl(tegra->sata_regs + SCFG_OFFSET + T_SATA0_CFG_SATA);
val &= ~T_SATA0_CFG_SATA_BACKDOOR_PROG_IF_EN;
writel(val, tegra->sata_regs + SCFG_OFFSET + T_SATA0_CFG_SATA);
- /* Enable IO & memory access, bus master mode */
-
- val = readl(tegra->sata_regs + SCFG_OFFSET + T_SATA0_CFG_1);
- val |= T_SATA0_CFG_1_IO_SPACE | T_SATA0_CFG_1_MEMORY_SPACE |
- T_SATA0_CFG_1_BUS_MASTER | T_SATA0_CFG_1_SERR;
- writel(val, tegra->sata_regs + SCFG_OFFSET + T_SATA0_CFG_1);
-
- /* Program SATA MMIO */
-
- writel(0x10000 << SATA_FPCI_BAR5_START_SHIFT,
- tegra->sata_regs + SATA_FPCI_BAR5);
+ /* Enabling LPM capabilities through Backdoor Programming */
+ val = readl(tegra->sata_regs + SCFG_OFFSET + T_SATA0_AHCI_HBA_CAP_BKDR);
+ val |= (T_SATA0_AHCI_HBA_CAP_BKDR_PARTIAL_ST_CAP |
+ T_SATA0_AHCI_HBA_CAP_BKDR_SLUMBER_ST_CAP |
+ T_SATA0_AHCI_HBA_CAP_BKDR_SALP |
+ T_SATA0_AHCI_HBA_CAP_BKDR_SUPP_PM);
+ writel(val, tegra->sata_regs + SCFG_OFFSET + T_SATA0_AHCI_HBA_CAP_BKDR);
+
+ /* SATA Second Level Clock Gating configuration
+ * Enabling Gating of Tx/Rx clocks and driving Pad IDDQ and Lane
+ * IDDQ Signals
+ */
+ val = readl(tegra->sata_regs + SCFG_OFFSET + T_SATA0_CFG_35);
+ val &= ~T_SATA0_CFG_35_IDP_INDEX_MASK;
+ val |= T_SATA0_CFG_35_IDP_INDEX;
+ writel(val, tegra->sata_regs + SCFG_OFFSET + T_SATA0_CFG_35);
+
+ val = T_SATA0_AHCI_IDP1_DATA;
+ writel(val, tegra->sata_regs + SCFG_OFFSET + T_SATA0_AHCI_IDP1);
+
+ val = readl(tegra->sata_regs + SCFG_OFFSET + T_SATA0_CFG_PHY_1);
+ val |= (T_SATA0_CFG_PHY_1_PADS_IDDQ_EN |
+ T_SATA0_CFG_PHY_1_PAD_PLL_IDDQ_EN);
+ writel(val, tegra->sata_regs + SCFG_OFFSET + T_SATA0_CFG_PHY_1);
+
+ /*
+ * Indicate Sata only has the capability to enter DevSleep
+ * from slumber link.
+ */
+
+ if (tegra->sata_aux_regs) {
+ val = readl(tegra->sata_aux_regs + SATA_AUX_MISC_CNTL_1_0);
+ val |= SATA_AUX_MISC_CNTL_1_0_DESO_SUPPORT;
+ writel(val, tegra->sata_aux_regs + SATA_AUX_MISC_CNTL_1_0);
+ }
- writel(0x08000 << T_SATA0_CFG_9_BASE_ADDRESS_SHIFT,
- tegra->sata_regs + SCFG_OFFSET + T_SATA0_CFG_9);
+ /* Enabling IPFS Clock Gating */
+ val = readl(tegra->sata_regs + SATA_CONFIGURATION_0);
+ val &= ~SATA_CONFIGURATION_0_CLK_OVERRIDE;
+ writel(val, tegra->sata_regs + SATA_CONFIGURATION_0);
- /* Unmask SATA interrupts */
+ tegra_ahci_handle_quirks(hpriv);
val = readl(tegra->sata_regs + SATA_INTR_MASK);
val |= SATA_INTR_MASK_IP_INT_MASK;
@@ -278,15 +460,22 @@ static struct ata_port_operations ahci_tegra_port_ops = {
.host_stop = tegra_ahci_host_stop,
};
-static const struct ata_port_info ahci_tegra_port_info = {
- .flags = AHCI_FLAG_COMMON,
+static struct ata_port_info ahci_tegra_port_info = {
+ .flags = AHCI_FLAG_COMMON | ATA_FLAG_NO_DIPM,
.pio_mask = ATA_PIO4,
.udma_mask = ATA_UDMA6,
.port_ops = &ahci_tegra_port_ops,
};
static const struct of_device_id tegra_ahci_of_match[] = {
- { .compatible = "nvidia,tegra124-ahci" },
+ {
+ .compatible = "nvidia,tegra124-ahci",
+ .data = &tegra124_ahci_soc_data
+ },
+ {
+ .compatible = "nvidia,tegra210-ahci",
+ .data = &tegra210_ahci_soc_data
+ },
{}
};
MODULE_DEVICE_TABLE(of, tegra_ahci_of_match);
@@ -295,12 +484,25 @@ static struct scsi_host_template ahci_platform_sht = {
AHCI_SHT(DRV_NAME),
};
+static void tegra_ahci_handle_quirks(struct ahci_host_priv *hpriv)
+{
+ struct tegra_ahci_priv *tegra = hpriv->plat_data;
+ u32 val;
+
+ if (tegra->sata_aux_regs && (tegra->soc_data->quirks & NO_DEVSLP)) {
+ val = readl(tegra->sata_aux_regs + SATA_AUX_MISC_CNTL_1_0);
+ val &= ~SATA_AUX_MISC_CNTL_1_0_SDS_SUPPORT;
+ writel(val, tegra->sata_aux_regs + SATA_AUX_MISC_CNTL_1_0);
+ }
+}
+
static int tegra_ahci_probe(struct platform_device *pdev)
{
struct ahci_host_priv *hpriv;
struct tegra_ahci_priv *tegra;
struct resource *res;
int ret;
+ unsigned int i;
hpriv = ahci_platform_get_resources(pdev);
if (IS_ERR(hpriv))
@@ -311,13 +513,25 @@ static int tegra_ahci_probe(struct platform_device *pdev)
return -ENOMEM;
hpriv->plat_data = tegra;
-
tegra->pdev = pdev;
+ tegra->soc_data =
+ (struct tegra_ahci_soc *)of_device_get_match_data(&pdev->dev);
res = platform_get_resource(pdev, IORESOURCE_MEM, 1);
tegra->sata_regs = devm_ioremap_resource(&pdev->dev, res);
if (IS_ERR(tegra->sata_regs))
return PTR_ERR(tegra->sata_regs);
+ res = platform_get_resource(pdev, IORESOURCE_MEM, 2);
+ /*
+ * Aux register is optional.
+ */
+ if (res) {
+ tegra->sata_aux_regs = devm_ioremap_resource(&pdev->dev, res);
+ if (IS_ERR(tegra->sata_aux_regs))
+ return PTR_ERR(tegra->sata_aux_regs);
+ } else {
+ tegra->sata_aux_regs = NULL;
+ }
tegra->sata_rst = devm_reset_control_get(&pdev->dev, "sata");
if (IS_ERR(tegra->sata_rst)) {
@@ -343,13 +557,17 @@ static int tegra_ahci_probe(struct platform_device *pdev)
return PTR_ERR(tegra->sata_clk);
}
- tegra->supplies[0].supply = "avdd";
- tegra->supplies[1].supply = "hvdd";
- tegra->supplies[2].supply = "vddio";
- tegra->supplies[3].supply = "target-5v";
- tegra->supplies[4].supply = "target-12v";
+ tegra->supplies = devm_kcalloc(&pdev->dev,
+ tegra->soc_data->num_supplies,
+ sizeof(*tegra->supplies), GFP_KERNEL);
+ if (!tegra->supplies)
+ return -ENOMEM;
+
+ for (i = 0; i < tegra->soc_data->num_supplies; i++)
+ tegra->supplies[i].supply = tegra->soc_data->supply_names[i];
- ret = devm_regulator_bulk_get(&pdev->dev, ARRAY_SIZE(tegra->supplies),
+ ret = devm_regulator_bulk_get(&pdev->dev,
+ tegra->soc_data->num_supplies,
tegra->supplies);
if (ret) {
dev_err(&pdev->dev, "Failed to get regulators\n");
@@ -385,5 +603,5 @@ static struct platform_driver tegra_ahci_driver = {
module_platform_driver(tegra_ahci_driver);
MODULE_AUTHOR("Mikko Perttunen <mperttunen-DDmLM1+adcrQT0dZR+AlfA@public.gmane.org>");
-MODULE_DESCRIPTION("Tegra124 AHCI SATA driver");
+MODULE_DESCRIPTION("Tegra AHCI SATA driver");
MODULE_LICENSE("GPL v2");
--
2.1.4
^ permalink raw reply related
* [PATCH V4 0/3] ADD AHCI support for tegra210
From: Preetham Chandru Ramchandra @ 2017-06-02 12:53 UTC (permalink / raw)
To: thierry.reding-Re5JQEeQqe8AvxtiuMwx3w, tj-DgEjT+Ai2ygdnm+yROfE0A,
cyndis-/1wQRMveznE
Cc: preetham260-Re5JQEeQqe8AvxtiuMwx3w,
linux-tegra-u79uwXL29TY76Z2rM5mHXA,
linux-ide-u79uwXL29TY76Z2rM5mHXA,
vbyravarasu-DDmLM1+adcrQT0dZR+AlfA,
pkunapuli-DDmLM1+adcrQT0dZR+AlfA, Preetham Chandru R
From: Preetham Chandru R <pchandru-DDmLM1+adcrQT0dZR+AlfA@public.gmane.org>
1. ADD AHCI support for tegra210
2. Extend the tegra AHCI controller device tree binding with tegra210
---
Preetham Chandru R (3):
ata: ahci_tegra: Add AHCI support for tegra210
arm64: tegra: Enable AHCI on Tegra210
dt-bindings: tegra: add binding documentation
.../bindings/ata/nvidia,tegra124-ahci.txt | 38 +-
arch/arm64/boot/dts/nvidia/tegra210-p2597.dtsi | 6 +
arch/arm64/boot/dts/nvidia/tegra210.dtsi | 16 +
drivers/ata/ahci_tegra.c | 386 ++++++++++++++++-----
4 files changed, 349 insertions(+), 97 deletions(-)
--
2.1.4
^ permalink raw reply
* [PATCH] ahci: qoriq: add ls1088a platforms support
From: Yuantian Tang @ 2017-06-02 7:23 UTC (permalink / raw)
To: tj; +Cc: linux-ide, linux-kernel, linux-arm-kernel, Yuantian Tang
Ls1088a is new introduced arm-based soc with sata support with
following features:
* Complies with the serial ATA 3.0 specification
and the AHCI 1.3.1 specification
* Contains a high-speed descriptor-based DMA controller
* Supports the following:
* Speeds of 1.5 Gb/s (first-generation SATA),
3 Gb/s (second-generation SATA), and 6 Gb/s (third-generation SATA)
* FIS-based switching
* Native command queuing (NCQ) commands
* Port multiplier operation
* Asynchronous notification
* SATA Vendor BIST mode
Signed-off-by: Tang Yuantian <andy.tang@nxp.com>
---
drivers/ata/ahci_qoriq.c | 14 ++++++++++++++
1 file changed, 14 insertions(+)
diff --git a/drivers/ata/ahci_qoriq.c b/drivers/ata/ahci_qoriq.c
index 4c96f3a..b6b0bf7 100644
--- a/drivers/ata/ahci_qoriq.c
+++ b/drivers/ata/ahci_qoriq.c
@@ -47,12 +47,14 @@
#define SATA_ECC_DISABLE 0x00020000
#define ECC_DIS_ARMV8_CH2 0x80000000
+#define ECC_DIS_LS1088A 0x40000000
enum ahci_qoriq_type {
AHCI_LS1021A,
AHCI_LS1043A,
AHCI_LS2080A,
AHCI_LS1046A,
+ AHCI_LS1088A,
AHCI_LS2088A,
};
@@ -68,6 +70,7 @@ static const struct of_device_id ahci_qoriq_of_match[] = {
{ .compatible = "fsl,ls1043a-ahci", .data = (void *)AHCI_LS1043A},
{ .compatible = "fsl,ls2080a-ahci", .data = (void *)AHCI_LS2080A},
{ .compatible = "fsl,ls1046a-ahci", .data = (void *)AHCI_LS1046A},
+ { .compatible = "fsl,ls1088a-ahci", .data = (void *)AHCI_LS1088A},
{ .compatible = "fsl,ls2088a-ahci", .data = (void *)AHCI_LS2088A},
{},
};
@@ -203,6 +206,17 @@ static int ahci_qoriq_phy_init(struct ahci_host_priv *hpriv)
writel(AHCI_PORT_AXICC_CFG, reg_base + PORT_AXICC);
break;
+ case AHCI_LS1088A:
+ if (!qpriv->ecc_addr)
+ return -EINVAL;
+ writel(readl(qpriv->ecc_addr) | ECC_DIS_LS1088A,
+ qpriv->ecc_addr);
+ writel(AHCI_PORT_PHY_1_CFG, reg_base + PORT_PHY1);
+ writel(AHCI_PORT_TRANS_CFG, reg_base + PORT_TRANS);
+ if (qpriv->is_dmacoherent)
+ writel(AHCI_PORT_AXICC_CFG, reg_base + PORT_AXICC);
+ break;
+
case AHCI_LS2088A:
writel(AHCI_PORT_PHY_1_CFG, reg_base + PORT_PHY1);
writel(AHCI_PORT_TRANS_CFG, reg_base + PORT_TRANS);
--
2.1.0.27.g96db324
^ permalink raw reply related
* Re: [PATCH libata/for-4.12-fixes] libata: fix error checking in in ata_parse_force_one()
From: Sergei Shtylyov @ 2017-06-01 9:03 UTC (permalink / raw)
To: Tejun Heo, Petru Mihancea; +Cc: linux-ide
In-Reply-To: <20170531183140.GB4795@htj.duckdns.org>
Hello!
s/in in/in/ in the subject. :-)
MBR, Sergei
^ permalink raw reply
* hi
From: griestkrist @ 2017-05-31 18:31 UTC (permalink / raw)
--
Please contact me in the my e-mail addres,(griestkrist1983@gmail.com)
^ permalink raw reply
* [PATCH libata/for-4.12-fixes] libata: fix error checking in in ata_parse_force_one()
From: Tejun Heo @ 2017-05-31 18:31 UTC (permalink / raw)
To: Petru Mihancea; +Cc: linux-ide
In-Reply-To: <CAKHFTdOvzO7W_NsDhqHVTN=FQCpuT61zXFjNRQ8y0YfTx1CY6Q@mail.gmail.com>
>From f7cf69ae171592d133c69b9adaa5de7cfb6038ea Mon Sep 17 00:00:00 2001
From: Tejun Heo <tj@kernel.org>
Date: Wed, 31 May 2017 14:26:26 -0400
ata_parse_force_one() was incorrectly comparing @p to @endp when it
should have been comparing @id. The only consequence is that it may
end up using an invalid port number in "libata.force" module param
instead of rejecting it.
Signed-off-by: Tejun Heo <tj@kernel.org>
Reported-by: Petru-Florin Mihancea <petrum@gmail.com>
Link: https://bugzilla.kernel.org/show_bug.cgi?id=195785
---
Applied to libata/for-4.12-fixes. Thanks.
drivers/ata/libata-core.c | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/drivers/ata/libata-core.c b/drivers/ata/libata-core.c
index 2d83b8c75965..e157a0e44419 100644
--- a/drivers/ata/libata-core.c
+++ b/drivers/ata/libata-core.c
@@ -6800,7 +6800,7 @@ static int __init ata_parse_force_one(char **cur,
}
force_ent->port = simple_strtoul(id, &endp, 10);
- if (p == endp || *endp != '\0') {
+ if (id == endp || *endp != '\0') {
*reason = "invalid port/link";
return -EINVAL;
}
--
2.13.0
^ permalink raw reply related
page: next (older) | prev (newer) | latest
- recent:[subjects (threaded)|topics (new)|topics (active)]
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox