mirror of
https://github.com/brain-hackers/u-boot-brain
synced 2024-08-22 01:48:52 +09:00
![Tom Rini](/assets/img/avatar_default.png)
When U-Boot started using SPDX tags we were among the early adopters and there weren't a lot of other examples to borrow from. So we picked the area of the file that usually had a full license text and replaced it with an appropriate SPDX-License-Identifier: entry. Since then, the Linux Kernel has adopted SPDX tags and they place it as the very first line in a file (except where shebangs are used, then it's second line) and with slightly different comment styles than us. In part due to community overlap, in part due to better tag visibility and in part for other minor reasons, switch over to that style. This commit changes all instances where we have a single declared license in the tag as both the before and after are identical in tag contents. There's also a few places where I found we did not have a tag and have introduced one. Signed-off-by: Tom Rini <trini@konsulko.com>
207 lines
5.4 KiB
C
207 lines
5.4 KiB
C
// SPDX-License-Identifier: GPL-2.0+
|
|
/*
|
|
* Copyright 2012 Calxeda, Inc.
|
|
*/
|
|
|
|
#include <common.h>
|
|
#include <ahci.h>
|
|
#include <asm/io.h>
|
|
|
|
#define CPHY_MAP(dev, addr) ((((dev) & 0x1f) << 7) | (((addr) >> 9) & 0x7f))
|
|
#define CPHY_ADDR(base, dev, addr) ((base) | (((addr) & 0x1ff) << 2))
|
|
#define CPHY_BASE 0xfff58000
|
|
#define CPHY_WIDTH 0x1000
|
|
#define CPHY_DTE_XS 5
|
|
#define CPHY_MII 31
|
|
#define SERDES_CR_CTL 0x80a0
|
|
#define SERDES_CR_ADDR 0x80a1
|
|
#define SERDES_CR_DATA 0x80a2
|
|
#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_TX_OVERRIDE_BIT 0x8000
|
|
#define CPHY_SATA_RX_OVERRIDE_BIT 0x4000
|
|
#define CPHY_TX_INPUT_OVERRIDE 0x2004
|
|
#define CPHY_RX_INPUT_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_TX_ATTEN 0x1c00
|
|
#define CPHY_SATA_TX_ATTEN_SHIFT 10
|
|
|
|
#define HB_SREG_SATA_ATTEN 0xfff3cf24
|
|
|
|
#define SATA_PORT_BASE 0xffe08000
|
|
#define SATA_VERSIONR 0xf8
|
|
#define SATA_HB_VERSION 0x3332302a
|
|
|
|
static u32 __combo_phy_reg_read(u8 phy, u8 dev, u32 addr)
|
|
{
|
|
u32 data;
|
|
writel(CPHY_MAP(dev, addr), CPHY_BASE + 0x800 + CPHY_WIDTH * phy);
|
|
data = readl(CPHY_ADDR(CPHY_BASE + CPHY_WIDTH * phy, dev, addr));
|
|
return data;
|
|
}
|
|
|
|
static void __combo_phy_reg_write(u8 phy, u8 dev, u32 addr, u32 data)
|
|
{
|
|
writel(CPHY_MAP(dev, addr), CPHY_BASE + 0x800 + CPHY_WIDTH * phy);
|
|
writel(data, CPHY_ADDR(CPHY_BASE + CPHY_WIDTH * phy, dev, addr));
|
|
}
|
|
|
|
static u32 combo_phy_read(u8 phy, u32 addr)
|
|
{
|
|
u8 dev = CPHY_DTE_XS;
|
|
if (phy == 5)
|
|
dev = CPHY_MII;
|
|
while (__combo_phy_reg_read(phy, dev, SERDES_CR_CTL) & CR_BUSY)
|
|
udelay(5);
|
|
__combo_phy_reg_write(phy, dev, SERDES_CR_ADDR, addr);
|
|
__combo_phy_reg_write(phy, dev, SERDES_CR_CTL, CR_START);
|
|
while (__combo_phy_reg_read(phy, dev, SERDES_CR_CTL) & CR_BUSY)
|
|
udelay(5);
|
|
return __combo_phy_reg_read(phy, dev, SERDES_CR_DATA);
|
|
}
|
|
|
|
static void combo_phy_write(u8 phy, u32 addr, u32 data)
|
|
{
|
|
u8 dev = CPHY_DTE_XS;
|
|
if (phy == 5)
|
|
dev = CPHY_MII;
|
|
while (__combo_phy_reg_read(phy, dev, SERDES_CR_CTL) & CR_BUSY)
|
|
udelay(5);
|
|
__combo_phy_reg_write(phy, dev, SERDES_CR_ADDR, addr);
|
|
__combo_phy_reg_write(phy, dev, SERDES_CR_DATA, data);
|
|
__combo_phy_reg_write(phy, dev, SERDES_CR_CTL, CR_WR_RDN | CR_START);
|
|
}
|
|
|
|
static void cphy_spread_spectrum_override(u8 phy, u8 lane, u32 val)
|
|
{
|
|
u32 tmp;
|
|
tmp = combo_phy_read(phy, CPHY_RX_INPUT_STS + lane * SPHY_LANE);
|
|
tmp &= ~CPHY_SATA_RX_OVERRIDE_BIT;
|
|
combo_phy_write(phy, CPHY_RX_INPUT_OVERRIDE + lane * SPHY_LANE, tmp);
|
|
|
|
tmp |= CPHY_SATA_RX_OVERRIDE_BIT;
|
|
combo_phy_write(phy, CPHY_RX_INPUT_OVERRIDE + lane * SPHY_LANE, tmp);
|
|
|
|
tmp &= ~CPHY_SATA_DPLL_MODE;
|
|
tmp |= (val << CPHY_SATA_DPLL_SHIFT) & CPHY_SATA_DPLL_MODE;
|
|
combo_phy_write(phy, CPHY_RX_INPUT_OVERRIDE + lane * SPHY_LANE, tmp);
|
|
}
|
|
|
|
static void cphy_tx_attenuation_override(u8 phy, u8 lane)
|
|
{
|
|
u32 val;
|
|
u32 tmp;
|
|
u8 shift;
|
|
|
|
shift = ((phy == 5) ? 4 : lane) * 4;
|
|
|
|
val = (readl(HB_SREG_SATA_ATTEN) >> shift) & 0xf;
|
|
|
|
if (val & 0x8)
|
|
return;
|
|
|
|
tmp = combo_phy_read(phy, CPHY_TX_INPUT_STS + lane * SPHY_LANE);
|
|
tmp &= ~CPHY_SATA_TX_OVERRIDE_BIT;
|
|
combo_phy_write(phy, CPHY_TX_INPUT_OVERRIDE + lane * SPHY_LANE, tmp);
|
|
|
|
tmp |= CPHY_SATA_TX_OVERRIDE_BIT;
|
|
combo_phy_write(phy, CPHY_TX_INPUT_OVERRIDE + lane * SPHY_LANE, tmp);
|
|
|
|
tmp |= (val << CPHY_SATA_TX_ATTEN_SHIFT) & CPHY_SATA_TX_ATTEN;
|
|
combo_phy_write(phy, CPHY_TX_INPUT_OVERRIDE + lane * SPHY_LANE, tmp);
|
|
}
|
|
|
|
static void cphy_disable_port_overrides(u8 port)
|
|
{
|
|
u32 tmp;
|
|
u8 lane = 0, phy = 0;
|
|
|
|
if (port == 0)
|
|
phy = 5;
|
|
else if (port < 5)
|
|
lane = port - 1;
|
|
else
|
|
return;
|
|
tmp = combo_phy_read(phy, CPHY_RX_INPUT_STS + lane * SPHY_LANE);
|
|
tmp &= ~CPHY_SATA_RX_OVERRIDE_BIT;
|
|
combo_phy_write(phy, CPHY_RX_INPUT_OVERRIDE + lane * SPHY_LANE, tmp);
|
|
|
|
tmp = combo_phy_read(phy, CPHY_TX_INPUT_OVERRIDE + lane * SPHY_LANE);
|
|
tmp &= ~CPHY_SATA_TX_OVERRIDE_BIT;
|
|
combo_phy_write(phy, CPHY_TX_INPUT_OVERRIDE + lane * SPHY_LANE, tmp);
|
|
}
|
|
|
|
void cphy_disable_overrides(void)
|
|
{
|
|
int i;
|
|
u32 port_map;
|
|
|
|
port_map = readl(0xffe08000 + HOST_PORTS_IMPL);
|
|
for (i = 0; i < 5; i++) {
|
|
if (port_map & (1 << i))
|
|
cphy_disable_port_overrides(i);
|
|
}
|
|
}
|
|
|
|
static void cphy_override_lane(u8 port)
|
|
{
|
|
u32 tmp, k = 0;
|
|
u8 lane = 0, phy = 0;
|
|
|
|
if (port == 0)
|
|
phy = 5;
|
|
else if (port < 5)
|
|
lane = port - 1;
|
|
else
|
|
return;
|
|
|
|
do {
|
|
tmp = combo_phy_read(0, CPHY_RX_INPUT_STS +
|
|
lane * SPHY_LANE);
|
|
} while ((tmp & SPHY_HALF_RATE) && (k++ < 1000));
|
|
cphy_spread_spectrum_override(phy, lane, 3);
|
|
cphy_tx_attenuation_override(phy, lane);
|
|
}
|
|
|
|
#define WAIT_MS_LINKUP 4
|
|
|
|
int ahci_link_up(struct ahci_uc_priv *probe_ent, int port)
|
|
{
|
|
u32 tmp;
|
|
int j = 0;
|
|
u8 *port_mmio = (u8 *)probe_ent->port[port].port_mmio;
|
|
u32 is_highbank = readl(SATA_PORT_BASE + SATA_VERSIONR) ==
|
|
SATA_HB_VERSION ? 1 : 0;
|
|
|
|
/* Bring up SATA link.
|
|
* SATA link bringup time is usually less than 1 ms; only very
|
|
* rarely has it taken between 1-2 ms. Never seen it above 2 ms.
|
|
*/
|
|
while (j < WAIT_MS_LINKUP) {
|
|
if (is_highbank && (j == 0)) {
|
|
cphy_disable_port_overrides(port);
|
|
writel(0x301, port_mmio + PORT_SCR_CTL);
|
|
udelay(1000);
|
|
writel(0x300, port_mmio + PORT_SCR_CTL);
|
|
udelay(1000);
|
|
cphy_override_lane(port);
|
|
}
|
|
|
|
tmp = readl(port_mmio + PORT_SCR_STAT);
|
|
if ((tmp & 0xf) == 0x3)
|
|
return 0;
|
|
udelay(1000);
|
|
j++;
|
|
|
|
if ((j == WAIT_MS_LINKUP) && (tmp & 0xf))
|
|
j = 0; /* retry phy reset */
|
|
}
|
|
return 1;
|
|
}
|