[<prev] [next>] [<thread-prev] [thread-next>] [day] [month] [year] [list]
Message-Id: <1375890758-30265-4-git-send-email-mark.langsdorf@calxeda.com>
Date: Wed, 7 Aug 2013 10:52:37 -0500
From: Mark Langsdorf <mark.langsdorf@...xeda.com>
To: linux-kernel@...r.kernel.org, linux-ide@...r.kernel.org,
tj@...nel.org, devicetree@...r.kernel.org, pawel.moll@....com,
mark.rutland@....com, swarren@...dotorg.org,
ian.campbell@...rix.com, rob.herring@...xeda.com,
sergei.shtylyov@...entembedded.com
Cc: Mark Langsdorf <mark.langsdorf@...xeda.com>
Subject: [PATCH v3 4/5] sata, highbank: set tx_atten override bits
Some board designs do not drive the SATA transmit lines within the
specification. The ECME can provide override settings, on a per board
basis, to bring the transmit lines within spec. Read those settings
from the DTB and program them in.
Signed-off-by: Mark Langsdorf <mark.langsdorf@...xeda.com>
---
Changes from v2
None.
Changes from v1
Clarified that the array is a u32 array.
Added an example in the bindings.
.../devicetree/bindings/ata/sata_highbank.txt | 5 +-
drivers/ata/sata_highbank.c | 58 +++++++++++++++++-----
2 files changed, 49 insertions(+), 14 deletions(-)
diff --git a/Documentation/devicetree/bindings/ata/sata_highbank.txt b/Documentation/devicetree/bindings/ata/sata_highbank.txt
index 1ac6d3d..fdbd4476 100644
--- a/Documentation/devicetree/bindings/ata/sata_highbank.txt
+++ b/Documentation/devicetree/bindings/ata/sata_highbank.txt
@@ -20,6 +20,9 @@ Optional properties:
indicator lights using the indicated GPIOs
- calxeda,led-order : a u32 array that map port numbers to offsets within the
SGPIO bitstream.
+- calxeda,tx-atten : a u32 array that contains TX attenuation override
+ codes, one per port. The upper 3 bytes are always
+ 0 and thus ignored.
Example:
sata@...08000 {
@@ -28,5 +31,5 @@ Example:
interrupts = <115>;
calxeda,port-phys = <&combophy5 0 &combophy0 0 &combophy0 1
&combophy0 2 &combophy0 3>;
-
+ calxeda,tx-atten = <0xff 22 0xff 0xff 23>;
};
diff --git a/drivers/ata/sata_highbank.c b/drivers/ata/sata_highbank.c
index 8b40025..a7c8038 100644
--- a/drivers/ata/sata_highbank.c
+++ b/drivers/ata/sata_highbank.c
@@ -46,14 +46,19 @@
#define CR_BUSY 0x0001
#define CR_START 0x0001
#define CR_WR_RDN 0x0002
+#define CPHY_TX_INPUT_STS 0x2001
#define CPHY_RX_INPUT_STS 0x2002
-#define CPHY_SATA_OVERRIDE 0x4000
-#define CPHY_OVERRIDE 0x2005
+#define CPHY_SATA_TX_OVERRIDE 0x8000
+#define CPHY_SATA_RX_OVERRIDE 0x4000
+#define CPHY_TX_OVERRIDE 0x2004
+#define CPHY_RX_OVERRIDE 0x2005
#define SPHY_LANE 0x100
#define SPHY_HALF_RATE 0x0001
#define CPHY_SATA_DPLL_MODE 0x0700
#define CPHY_SATA_DPLL_SHIFT 8
#define CPHY_SATA_DPLL_RESET (1 << 11)
+#define CPHY_SATA_TX_ATTEN 0x1c00
+#define CPHY_SATA_TX_ATTEN_SHIFT 10
#define CPHY_PHY_COUNT 6
#define CPHY_LANE_COUNT 4
#define CPHY_PORT_COUNT (CPHY_PHY_COUNT * CPHY_LANE_COUNT)
@@ -66,6 +71,7 @@ struct phy_lane_info {
void __iomem *phy_base;
u8 lane_mapping;
u8 phy_devs;
+ u8 tx_atten;
};
static struct phy_lane_info port_data[CPHY_PORT_COUNT];
@@ -76,7 +82,6 @@ static DEFINE_SPINLOCK(sgpio_lock);
#define SGPIO_PINS 3
#define SGPIO_PORTS 8
-/* can be cast as an ahci_host_priv for compatibility with most functions */
struct ecx_plat_data {
u32 n_ports;
unsigned sgpio_gpio[SGPIO_PINS];
@@ -259,8 +264,27 @@ static void highbank_cphy_disable_overrides(u8 sata_port)
if (unlikely(port_data[sata_port].phy_base == NULL))
return;
tmp = combo_phy_read(sata_port, CPHY_RX_INPUT_STS + lane * SPHY_LANE);
- tmp &= ~CPHY_SATA_OVERRIDE;
- combo_phy_write(sata_port, CPHY_OVERRIDE + lane * SPHY_LANE, tmp);
+ tmp &= ~CPHY_SATA_RX_OVERRIDE;
+ combo_phy_write(sata_port, CPHY_RX_OVERRIDE + lane * SPHY_LANE, tmp);
+}
+
+static void cphy_override_tx_attenuation(u8 sata_port, u32 val)
+{
+ u8 lane = port_data[sata_port].lane_mapping;
+ u32 tmp;
+
+ if (val & 0x8)
+ return;
+
+ tmp = combo_phy_read(sata_port, CPHY_TX_INPUT_STS + lane * SPHY_LANE);
+ tmp &= ~CPHY_SATA_TX_OVERRIDE;
+ combo_phy_write(sata_port, CPHY_TX_OVERRIDE + lane * SPHY_LANE, tmp);
+
+ tmp |= CPHY_SATA_TX_OVERRIDE;
+ combo_phy_write(sata_port, CPHY_TX_OVERRIDE + lane * SPHY_LANE, tmp);
+
+ tmp |= (val << CPHY_SATA_TX_ATTEN_SHIFT) & CPHY_SATA_TX_ATTEN;
+ combo_phy_write(sata_port, CPHY_TX_OVERRIDE + lane * SPHY_LANE, tmp);
}
static void cphy_override_rx_mode(u8 sata_port, u32 val)
@@ -268,21 +292,21 @@ static void cphy_override_rx_mode(u8 sata_port, u32 val)
u8 lane = port_data[sata_port].lane_mapping;
u32 tmp;
tmp = combo_phy_read(sata_port, CPHY_RX_INPUT_STS + lane * SPHY_LANE);
- tmp &= ~CPHY_SATA_OVERRIDE;
- combo_phy_write(sata_port, CPHY_OVERRIDE + lane * SPHY_LANE, tmp);
+ tmp &= ~CPHY_SATA_RX_OVERRIDE;
+ combo_phy_write(sata_port, CPHY_RX_OVERRIDE + lane * SPHY_LANE, tmp);
- tmp |= CPHY_SATA_OVERRIDE;
- combo_phy_write(sata_port, CPHY_OVERRIDE + lane * SPHY_LANE, tmp);
+ tmp |= CPHY_SATA_RX_OVERRIDE;
+ combo_phy_write(sata_port, CPHY_RX_OVERRIDE + lane * SPHY_LANE, tmp);
tmp &= ~CPHY_SATA_DPLL_MODE;
tmp |= val << CPHY_SATA_DPLL_SHIFT;
- combo_phy_write(sata_port, CPHY_OVERRIDE + lane * SPHY_LANE, tmp);
+ combo_phy_write(sata_port, CPHY_RX_OVERRIDE + lane * SPHY_LANE, tmp);
tmp |= CPHY_SATA_DPLL_RESET;
- combo_phy_write(sata_port, CPHY_OVERRIDE + lane * SPHY_LANE, tmp);
+ combo_phy_write(sata_port, CPHY_RX_OVERRIDE + lane * SPHY_LANE, tmp);
tmp &= ~CPHY_SATA_DPLL_RESET;
- combo_phy_write(sata_port, CPHY_OVERRIDE + lane * SPHY_LANE, tmp);
+ combo_phy_write(sata_port, CPHY_RX_OVERRIDE + lane * SPHY_LANE, tmp);
msleep(15);
}
@@ -299,16 +323,20 @@ static void highbank_cphy_override_lane(u8 sata_port)
lane * SPHY_LANE);
} while ((tmp & SPHY_HALF_RATE) && (k++ < 1000));
cphy_override_rx_mode(sata_port, 3);
+ cphy_override_tx_attenuation(sata_port, port_data[sata_port].tx_atten);
}
static int highbank_initialize_phys(struct device *dev, void __iomem *addr)
{
struct device_node *sata_node = dev->of_node;
- int phy_count = 0, phy, port = 0;
+ int phy_count = 0, phy, port = 0, i;
void __iomem *cphy_base[CPHY_PHY_COUNT];
struct device_node *phy_nodes[CPHY_PHY_COUNT];
+ u32 tx_atten[CPHY_PORT_COUNT];
+
memset(port_data, 0, sizeof(struct phy_lane_info) * CPHY_PORT_COUNT);
memset(phy_nodes, 0, sizeof(struct device_node*) * CPHY_PHY_COUNT);
+ memset(tx_atten, 0xff, CPHY_PORT_COUNT);
do {
u32 tmp;
@@ -336,6 +364,10 @@ static int highbank_initialize_phys(struct device *dev, void __iomem *addr)
of_node_put(phy_data.np);
port += 1;
} while (port < CPHY_PORT_COUNT);
+ of_property_read_u32_array(sata_node, "calxeda,tx-atten",
+ tx_atten, port);
+ for (i = 0; i < port; i++)
+ port_data[i].tx_atten = (u8) tx_atten[i];
return 0;
}
--
1.8.1.2
--
To unsubscribe from this list: send the line "unsubscribe linux-kernel" in
the body of a message to majordomo@...r.kernel.org
More majordomo info at http://vger.kernel.org/majordomo-info.html
Please read the FAQ at http://www.tux.org/lkml/
Powered by blists - more mailing lists