* [U-Boot] [PATCH v2 0/4] Support for SATA on EXYNOS5
@ 2012-11-23 12:08 Vasanth Ananthan
2012-11-23 12:08 ` [U-Boot] [PATCH v2 1/4] Exynos5: Add clock support for SATA Vasanth Ananthan
` (3 more replies)
0 siblings, 4 replies; 6+ messages in thread
From: Vasanth Ananthan @ 2012-11-23 12:08 UTC (permalink / raw)
To: u-boot
This patch set adds support for SATA on Exynos5250
Vasanth Ananthan (4):
Exynos5: Add clock support for SATA
Exynos5: Add base addresses for SATA
Drivers: block: Support for SATA in Exynos5
SMDK55250: Enable SATA
arch/arm/cpu/armv7/exynos/clock.c | 22 ++
arch/arm/include/asm/arch-exynos/clk.h | 1 +
arch/arm/include/asm/arch-exynos/cpu.h | 3 +
arch/arm/include/asm/arch-exynos/periph.h | 1 +
drivers/block/dwc_ahsata.c | 394 ++++++++++++++++++++++++++++-
include/configs/smdk5250.h | 11 +
6 files changed, 425 insertions(+), 7 deletions(-)
--
1.7.9.5
^ permalink raw reply [flat|nested] 6+ messages in thread
* [U-Boot] [PATCH v2 1/4] Exynos5: Add clock support for SATA
2012-11-23 12:08 [U-Boot] [PATCH v2 0/4] Support for SATA on EXYNOS5 Vasanth Ananthan
@ 2012-11-23 12:08 ` Vasanth Ananthan
2012-11-23 12:08 ` [U-Boot] [PATCH v2 2/4] Exynos5: Add base addresses " Vasanth Ananthan
` (2 subsequent siblings)
3 siblings, 0 replies; 6+ messages in thread
From: Vasanth Ananthan @ 2012-11-23 12:08 UTC (permalink / raw)
To: u-boot
This patch adds clock support for SATA
Signed-off-by: Vasanth Ananthan <vasanth.a@samsung.com>
---
arch/arm/cpu/armv7/exynos/clock.c | 22 ++++++++++++++++++++++
arch/arm/include/asm/arch-exynos/clk.h | 1 +
2 files changed, 23 insertions(+)
diff --git a/arch/arm/cpu/armv7/exynos/clock.c b/arch/arm/cpu/armv7/exynos/clock.c
index fe61f88..22b327b 100644
--- a/arch/arm/cpu/armv7/exynos/clock.c
+++ b/arch/arm/cpu/armv7/exynos/clock.c
@@ -26,6 +26,7 @@
#include <asm/arch/clock.h>
#include <asm/arch/clk.h>
#include <asm/arch/periph.h>
+#include <asm/errno.h>
/* Epll Clock division values to achive different frequency output */
static struct set_epll_con_val exynos5_epll_div[] = {
@@ -326,6 +327,19 @@ static unsigned long exynos4_get_uart_clk(int dev_index)
return uclk;
}
+static unsigned long exynos5_get_sata_clk(void)
+{
+ struct exynos5_clock *clk =
+ (struct exynos5_clock *)samsung_get_base_clock();
+
+ /*
+ * This clock is used as a input for 1ms timer, so return
+ * the clock equivalent to 1 MHz
+ */
+
+ return CONFIG_SYS_CLK_FREQ / 10;
+}
+
/* exynos5: return uart clock frequency */
static unsigned long exynos5_get_uart_clk(int dev_index)
{
@@ -963,6 +977,14 @@ unsigned long get_uart_clk(int dev_index)
return exynos4_get_uart_clk(dev_index);
}
+unsigned long get_sata_clock(void)
+{
+ if (cpu_is_exynos5())
+ return exynos5_get_sata_clk();
+
+ return -ENOSYS;
+}
+
void set_mmc_clk(int dev_index, unsigned int div)
{
if (cpu_is_exynos5())
diff --git a/arch/arm/include/asm/arch-exynos/clk.h b/arch/arm/include/asm/arch-exynos/clk.h
index cd12323..182ed95 100644
--- a/arch/arm/include/asm/arch-exynos/clk.h
+++ b/arch/arm/include/asm/arch-exynos/clk.h
@@ -42,5 +42,6 @@ void set_i2s_clk_source(void);
int set_i2s_clk_prescaler(unsigned int src_frq, unsigned int dst_frq);
int set_epll_clk(unsigned long rate);
int set_spi_clk(int periph_id, unsigned int rate);
+unsigned long get_sata_clk(void);
#endif
--
1.7.9.5
^ permalink raw reply related [flat|nested] 6+ messages in thread
* [U-Boot] [PATCH v2 2/4] Exynos5: Add base addresses for SATA
2012-11-23 12:08 [U-Boot] [PATCH v2 0/4] Support for SATA on EXYNOS5 Vasanth Ananthan
2012-11-23 12:08 ` [U-Boot] [PATCH v2 1/4] Exynos5: Add clock support for SATA Vasanth Ananthan
@ 2012-11-23 12:08 ` Vasanth Ananthan
2012-11-23 12:08 ` [U-Boot] [PATCH v2 3/4] Drivers: block: Support for SATA in Exynos5 Vasanth Ananthan
2012-11-23 12:08 ` [U-Boot] [PATCH v2 4/4] SMDK55250: Enable SATA Vasanth Ananthan
3 siblings, 0 replies; 6+ messages in thread
From: Vasanth Ananthan @ 2012-11-23 12:08 UTC (permalink / raw)
To: u-boot
This patch adds the macro definition of SATA controller and PHY controller
base addresses.
Signed-off-by: Vasanth Ananthan <vasanth.a@samsung.com>
---
arch/arm/include/asm/arch-exynos/cpu.h | 3 +++
arch/arm/include/asm/arch-exynos/periph.h | 1 +
2 files changed, 4 insertions(+)
diff --git a/arch/arm/include/asm/arch-exynos/cpu.h b/arch/arm/include/asm/arch-exynos/cpu.h
index d1b2ea8..6ea1230 100644
--- a/arch/arm/include/asm/arch-exynos/cpu.h
+++ b/arch/arm/include/asm/arch-exynos/cpu.h
@@ -80,8 +80,11 @@
#define EXYNOS5_USB_HOST_EHCI_BASE 0x12110000
#define EXYNOS5_USBPHY_BASE 0x12130000
#define EXYNOS5_USBOTG_BASE 0x12140000
+#define EXYNOS5_SATA_PHY_BASE 0x12170000
+#define EXYNOS5_SATA_PHY_I2C 0x121D0000
#define EXYNOS5_MMC_BASE 0x12200000
#define EXYNOS5_SROMC_BASE 0x12250000
+#define EXYNOS5_SATA_BASE 0x122F0000
#define EXYNOS5_UART_BASE 0x12C00000
#define EXYNOS5_I2C_BASE 0x12C60000
#define EXYNOS5_SPI_BASE 0x12D20000
diff --git a/arch/arm/include/asm/arch-exynos/periph.h b/arch/arm/include/asm/arch-exynos/periph.h
index 13abd2d..58dc675 100644
--- a/arch/arm/include/asm/arch-exynos/periph.h
+++ b/arch/arm/include/asm/arch-exynos/periph.h
@@ -54,6 +54,7 @@ enum periph_id {
PERIPH_ID_UART1,
PERIPH_ID_UART2,
PERIPH_ID_UART3,
+ PERIPH_ID_SATA,
PERIPH_ID_COUNT,
PERIPH_ID_NONE = -1,
--
1.7.9.5
^ permalink raw reply related [flat|nested] 6+ messages in thread
* [U-Boot] [PATCH v2 3/4] Drivers: block: Support for SATA in Exynos5
2012-11-23 12:08 [U-Boot] [PATCH v2 0/4] Support for SATA on EXYNOS5 Vasanth Ananthan
2012-11-23 12:08 ` [U-Boot] [PATCH v2 1/4] Exynos5: Add clock support for SATA Vasanth Ananthan
2012-11-23 12:08 ` [U-Boot] [PATCH v2 2/4] Exynos5: Add base addresses " Vasanth Ananthan
@ 2012-11-23 12:08 ` Vasanth Ananthan
2012-11-23 15:41 ` Luka Perkov
2012-11-23 12:08 ` [U-Boot] [PATCH v2 4/4] SMDK55250: Enable SATA Vasanth Ananthan
3 siblings, 1 reply; 6+ messages in thread
From: Vasanth Ananthan @ 2012-11-23 12:08 UTC (permalink / raw)
To: u-boot
This patch provides support for SATA in Exynos5250
Signed-off-by: Vasanth Ananthan <vasanth.a@samsung.com>
---
drivers/block/dwc_ahsata.c | 394 +++++++++++++++++++++++++++++++++++++++++++-
1 file changed, 387 insertions(+), 7 deletions(-)
diff --git a/drivers/block/dwc_ahsata.c b/drivers/block/dwc_ahsata.c
index c9b71f7..5125134 100644
--- a/drivers/block/dwc_ahsata.c
+++ b/drivers/block/dwc_ahsata.c
@@ -35,6 +35,69 @@
#include <asm/arch/clock.h>
#include "dwc_ahsata.h"
+
+#define bool unsigned char
+#define false 0
+#define true 1
+
+#ifdef SATA_DEBUG
+#define debug(fmt, args...) printf(fmt, ##args)
+#else
+#define debug(fmt, args...)
+#endif /* MKIMAGE_DEBUG */
+
+#define MAX_DATA_BYTES_PER_SG (4 * 1024 * 1024)
+#define MAX_BYTES_PER_TRANS (AHCI_MAX_SG * MAX_DATA_BYTES_PER_SG)
+
+#define writel_with_flush(a, b) do { writel(a, b); readl(b); } while (0)
+
+#define EXYNOS5_SATA_PHY_CONTROL (0x10040000 + 0x724)
+#define S5P_PMU_SATA_PHY_CONTROL_EN 0x1
+
+#define SATA_TIME_LIMIT 10000
+#define SATA_PHY_I2C_SLAVE_ADDRS 0x70
+
+#define SATA_RESET 0x4
+#define RESET_CMN_RST_N (1 << 1)
+#define LINK_RESET 0xF0000
+
+#define SATA_MODE0 0x10
+
+#define SATA_CTRL0 0x14
+#define CTRL0_P0_PHY_CALIBRATED_SEL (1 << 9)
+#define CTRL0_P0_PHY_CALIBRATED (1 << 8)
+
+#define SATA_PHSATA_CTRLM 0xE0
+#define PHCTRLM_REF_RATE (1 << 1)
+#define PHCTRLM_HIGH_SPEED (1 << 0)
+
+#define SATA_PHSATA_STATM 0xF0
+#define PHSTATM_PLL_LOCKED (1 << 0)
+
+#define SATA_I2C_CON 0x00
+#define SATA_I2C_STAT 0x04
+#define SATA_I2C_ADDR 0x08
+#define SATA_I2C_DS 0x0C
+#define SATA_I2C_LC 0x10
+
+/* I2CCON reg */
+#define CON_ACKEN (1 << 7)
+#define CON_CLK512 (1 << 6)
+#define CON_CLK16 (~CON_CLK512)
+#define CON_INTEN (1 << 5)
+#define CON_INTPND (1 << 4)
+#define CON_TXCLK_PS (0xF)
+
+/* I2CSTAT reg */
+#define STAT_MSTT (0x3 << 6)
+#define STAT_BSYST (1 << 5)
+#define STAT_RTEN (1 << 4)
+#define STAT_LAST (1 << 0)
+
+#define LC_FLTR_EN (1 << 2)
+
+#define SATA_PHY_CON_RESET 0xF003F
+
struct sata_port_regs {
u32 clb;
u32 clbu;
@@ -88,10 +151,244 @@ struct sata_host_regs {
u32 idr;
};
-#define MAX_DATA_BYTES_PER_SG (4 * 1024 * 1024)
-#define MAX_BYTES_PER_TRANS (AHCI_MAX_SG * MAX_DATA_BYTES_PER_SG)
+void * const phy_ctrl = (void *)EXYNOS5_SATA_PHY_BASE;
+void * const phy_i2c_base = (void *)EXYNOS5_SATA_PHY_I2C;
-#define writel_with_flush(a, b) do { writel(a, b); readl(b); } while (0)
+enum {
+ SATA_GENERATION1,
+ SATA_GENERATION2,
+ SATA_GENERATION3,
+};
+
+static bool sata_is_reg(void *base, u32 reg, u32 checkbit, u32 status)
+{
+ if ((readl(base + reg) & checkbit) == status)
+ return true;
+ else
+ return false;
+}
+
+static bool wait_for_reg_status(void *base, u32 reg, u32 checkbit,
+ u32 status)
+{
+ u32 time_limit_cnt = 0;
+ while (!sata_is_reg(base, reg, checkbit, status)) {
+ if (time_limit_cnt == SATA_TIME_LIMIT)
+ return false;
+ udelay(1000);
+ time_limit_cnt++;
+ }
+ return true;
+}
+
+static void sata_set_gen(u8 gen)
+{
+ writel(gen, phy_ctrl + SATA_MODE0);
+}
+
+/* Address :I2C Address */
+static void sata_i2c_write_addrs(u8 data)
+{
+ writeb((data & 0xFE), phy_i2c_base + SATA_I2C_DS);
+}
+
+static void sata_i2c_write_data(u8 data)
+{
+ writeb((data), phy_i2c_base + SATA_I2C_DS);
+}
+
+static void sata_i2c_start(void)
+{
+ u32 val;
+ val = readl(phy_i2c_base + SATA_I2C_STAT);
+ val |= STAT_BSYST;
+ writel(val, phy_i2c_base + SATA_I2C_STAT);
+}
+
+static void sata_i2c_stop(void)
+{
+ u32 val;
+ val = readl(phy_i2c_base + SATA_I2C_STAT);
+ val &= ~STAT_BSYST;
+ writel(val, phy_i2c_base + SATA_I2C_STAT);
+}
+
+static bool sata_i2c_get_int_status(void)
+{
+ if ((readl(phy_i2c_base + SATA_I2C_CON)) & CON_INTPND)
+ return true;
+ else
+ return false;
+}
+
+static bool sata_i2c_is_tx_ack(void)
+{
+ if ((readl(phy_i2c_base + SATA_I2C_STAT)) & STAT_LAST)
+ return false;
+ else
+ return true;
+}
+
+static bool sata_i2c_is_bus_ready(void)
+{
+ if ((readl(phy_i2c_base + SATA_I2C_STAT)) & STAT_BSYST)
+ return false;
+ else
+ return true;
+}
+
+static bool sata_i2c_wait_for_busready(u32 time_out)
+{
+ while (--time_out) {
+ if (sata_i2c_is_bus_ready())
+ return true;
+ udelay(100);
+ }
+ return false;
+}
+
+static bool sata_i2c_wait_for_tx_ack(u32 time_out)
+{
+ while (--time_out) {
+ if (sata_i2c_get_int_status()) {
+ if (sata_i2c_is_tx_ack())
+ return true;
+ }
+ udelay(100);
+ }
+ return false;
+}
+
+static void sata_i2c_clear_int_status(void)
+{
+ u32 val;
+ val = readl(phy_i2c_base + SATA_I2C_CON);
+ val &= ~CON_INTPND;
+ writel(val, phy_i2c_base + SATA_I2C_CON);
+}
+
+
+static void sata_i2c_set_ack_gen(bool enable)
+{
+ u32 val;
+ if (enable) {
+ val = (readl(phy_i2c_base + SATA_I2C_CON)) | CON_ACKEN;
+ writel(val, phy_i2c_base + SATA_I2C_CON);
+ } else {
+ val = readl(phy_i2c_base + SATA_I2C_CON);
+ val &= ~CON_ACKEN;
+ writel(val, phy_i2c_base + SATA_I2C_CON);
+ }
+
+}
+
+static void sata_i2c_set_master_tx(void)
+{
+ u32 val;
+ /* Disable I2C */
+ val = readl(phy_i2c_base + SATA_I2C_STAT);
+ val &= ~STAT_RTEN;
+ writel(val, phy_i2c_base + SATA_I2C_STAT);
+ /* Clear Mode */
+ val = readl(phy_i2c_base + SATA_I2C_STAT);
+ val &= ~STAT_MSTT;
+ writel(val, phy_i2c_base + SATA_I2C_STAT);
+ sata_i2c_clear_int_status();
+ /* interrupt disable */
+ val = readl(phy_i2c_base + SATA_I2C_CON);
+ val &= ~CON_INTEN;
+ writel(val, phy_i2c_base + SATA_I2C_CON);
+
+ /* Master, Send mode */
+ val = readl(phy_i2c_base + SATA_I2C_STAT);
+ val |= STAT_MSTT;
+ writel(val, phy_i2c_base + SATA_I2C_STAT);
+
+ /* interrupt enable */
+ val = readl(phy_i2c_base + SATA_I2C_CON);
+ val |= CON_INTEN;
+ writel(val, phy_i2c_base + SATA_I2C_CON);
+
+ /* Enable I2C */
+ val = readl(phy_i2c_base + SATA_I2C_STAT);
+ val |= STAT_RTEN;
+ writel(val, phy_i2c_base + SATA_I2C_STAT);
+}
+
+static void sata_i2c_init(void)
+{
+ u32 val;
+
+ val = readl(phy_i2c_base + SATA_I2C_CON);
+ val &= CON_CLK16;
+ writel(val, phy_i2c_base + SATA_I2C_CON);
+
+ val = readl(phy_i2c_base + SATA_I2C_CON);
+ val &= ~(CON_TXCLK_PS);
+ writel(val, phy_i2c_base + SATA_I2C_CON);
+
+ val = readl(phy_i2c_base + SATA_I2C_CON);
+ val |= (2 & CON_TXCLK_PS);
+ writel(val, phy_i2c_base + SATA_I2C_CON);
+
+ val = readl(phy_i2c_base + SATA_I2C_LC);
+ val &= ~(LC_FLTR_EN);
+ writel(val, phy_i2c_base + SATA_I2C_LC);
+
+ sata_i2c_set_ack_gen(false);
+}
+
+static bool sata_i2c_send(u8 slave_addrs, u8 addrs, u8 ucData)
+{
+ s32 ret = 0;
+ if (!sata_i2c_wait_for_busready(SATA_TIME_LIMIT))
+ return false;
+
+ sata_i2c_init();
+ sata_i2c_set_master_tx();
+
+ writel(SATA_PHY_CON_RESET, phy_ctrl + SATA_RESET);
+ sata_i2c_write_addrs(slave_addrs);
+ sata_i2c_start();
+ if (!sata_i2c_wait_for_tx_ack(SATA_TIME_LIMIT)) {
+ ret = false;
+ goto STOP;
+ }
+ sata_i2c_write_data(addrs);
+ sata_i2c_clear_int_status();
+ if (!sata_i2c_wait_for_tx_ack(SATA_TIME_LIMIT)) {
+ ret = false;
+ goto STOP;
+ }
+ sata_i2c_write_data(ucData);
+ sata_i2c_clear_int_status();
+ if (!sata_i2c_wait_for_tx_ack(SATA_TIME_LIMIT)) {
+ ret = false;
+ goto STOP;
+ }
+ ret = true;
+
+STOP:
+ sata_i2c_stop();
+ sata_i2c_clear_int_status();
+ sata_i2c_wait_for_busready(SATA_TIME_LIMIT);
+
+ return ret;
+}
+
+static bool sata_phy_i2c_init()
+{
+ /* 0x3A for 40bit I/F */
+ u8 reg_addrs = 0x3A;
+ /* 0x0B for 40bit I/F */
+ u8 default_setting_value = 0x0B;
+
+ if (!sata_i2c_send(SATA_PHY_I2C_SLAVE_ADDRS, reg_addrs,
+ default_setting_value))
+ return false;
+
+ return true;
+}
static int is_ready;
@@ -127,6 +424,58 @@ static int ahci_setup_oobr(struct ahci_probe_ent *probe_ent,
return 0;
}
+static int sata_phy_init(int port_num)
+{
+ int val, ret;
+
+ writel(S5P_PMU_SATA_PHY_CONTROL_EN, EXYNOS5_SATA_PHY_CONTROL);
+
+ val = 0;
+ writel(val, phy_ctrl + SATA_RESET);
+ val = readl(phy_ctrl + SATA_RESET);
+ val |= 0x3D;
+ writel(val, phy_ctrl + SATA_RESET);
+
+ val = readl(phy_ctrl + SATA_RESET);
+ val |= LINK_RESET;
+ writel(val, phy_ctrl + SATA_RESET);
+
+ val = readl(phy_ctrl + SATA_RESET);
+ val |= RESET_CMN_RST_N;
+ writel(val, phy_ctrl + SATA_RESET);
+
+ val = readl(phy_ctrl + SATA_PHSATA_CTRLM);
+ val &= ~PHCTRLM_REF_RATE;
+ writel(val, phy_ctrl + SATA_PHSATA_CTRLM);
+
+ /* High speed enable for Gen3 */
+ val = readl(phy_ctrl + SATA_PHSATA_CTRLM);
+ val |= PHCTRLM_HIGH_SPEED;
+ writel(val, phy_ctrl + SATA_PHSATA_CTRLM);
+
+ ret = sata_phy_i2c_init();
+
+ val = readl(phy_ctrl + SATA_CTRL0);
+ val |= CTRL0_P0_PHY_CALIBRATED_SEL|CTRL0_P0_PHY_CALIBRATED;
+ writel(val, phy_ctrl + SATA_CTRL0);
+ sata_set_gen(SATA_GENERATION3);
+
+ /* release cmu reset */
+ val = readl(phy_ctrl + SATA_RESET);
+ val &= ~RESET_CMN_RST_N;
+ writel(val, phy_ctrl + SATA_RESET);
+
+ val = readl(phy_ctrl + SATA_RESET);
+ val |= RESET_CMN_RST_N;
+ writel(val, phy_ctrl + SATA_RESET);
+
+ if (wait_for_reg_status(phy_ctrl, SATA_PHSATA_STATM,
+ PHSTATM_PLL_LOCKED, 1)) {
+ return ret;
+ }
+ return 0;
+}
+
static int ahci_host_init(struct ahci_probe_ent *probe_ent)
{
u32 tmp, cap_save, num_ports;
@@ -134,10 +483,11 @@ static int ahci_host_init(struct ahci_probe_ent *probe_ent)
struct sata_port_regs *port_mmio = NULL;
struct sata_host_regs *host_mmio =
(struct sata_host_regs *)probe_ent->mmio_base;
- int clk = mxc_get_clock(MXC_SATA_CLK);
+ int clk = get_sata_clock();
cap_save = readl(&(host_mmio->cap));
cap_save |= SATA_HOST_CAP_SSS;
+ cap_save &= ~(SATA_HOST_CAP_SMPS);
/* global controller reset */
tmp = readl(&(host_mmio->ghc));
@@ -159,7 +509,7 @@ static int ahci_host_init(struct ahci_probe_ent *probe_ent)
ahci_setup_oobr(probe_ent, 0);
writel_with_flush(SATA_HOST_GHC_AE, &(host_mmio->ghc));
- writel(cap_save, &(host_mmio->cap));
+ writel_with_flush(cap_save, &(host_mmio->cap));
num_ports = (cap_save & SATA_HOST_CAP_NP_MASK) + 1;
writel_with_flush((1 << num_ports) - 1,
&(host_mmio->pi));
@@ -219,11 +569,37 @@ static int ahci_host_init(struct ahci_probe_ent *probe_ent)
debug("port reset failed (0x%x)\n", tmp);
return -1;
}
+
+ tmp &= ~SATA_PORT_CMD_FRE;
+ writel_with_flush(tmp, &(port_mmio->cmd));
+
+ timeout = 1000;
+
+ while ((readl(&(port_mmio->cmd)) & SATA_PORT_CMD_FR)
+ && --timeout)
+ ;
+
+ if (timeout <= 0) {
+ debug("port reset failed (0x%x)\n", tmp);
+ return -1;
+ }
}
+ tmp = readl(&(port_mmio->sctl));
+ tmp &= (SATA_PORT_SSTS_DET_MASK);
+ writel_with_flush(tmp, &(port_mmio->sctl));
+
/* Spin-up device */
tmp = readl(&(port_mmio->cmd));
- writel((tmp | SATA_PORT_CMD_SUD), &(port_mmio->cmd));
+
+ tmp |= (SATA_PORT_CMD_SUD |
+ SATA_PORT_CMD_HPCP);
+
+ tmp &= ~(SATA_PORT_CMD_MPSP |
+ SATA_PORT_CMD_CPD |
+ SATA_PORT_CMD_ESP);
+
+ writel(tmp, &(port_mmio->cmd));
/* Wait for spin-up to finish */
timeout = 1000;
@@ -235,6 +611,8 @@ static int ahci_host_init(struct ahci_probe_ent *probe_ent)
return -1;
}
+ sata_phy_init(i);
+
for (j = 0; j < 100; ++j) {
mdelay(10);
tmp = readl(&(port_mmio->ssts));
@@ -273,7 +651,7 @@ static int ahci_host_init(struct ahci_probe_ent *probe_ent)
/* set irq mask (enables interrupts) */
writel(DEF_PORT_IRQ, &(port_mmio->ie));
-
+ mdelay(100);
/* register linkup ports */
tmp = readl(&(port_mmio->ssts));
debug("Port %d status: 0x%x\n", i, tmp);
@@ -941,11 +1319,13 @@ int scan_sata(int dev)
pdev->blksz = ATA_SECT_SIZE;
pdev->lun = 0 ;
+#ifdef CONFIG_LBA48
/* Check if support LBA48 */
if (ata_id_has_lba48(id)) {
pdev->lba48 = 1;
debug("Device support LBA48\n\r");
}
+#endif
/* Get the NCQ queue depth from device */
probe_ent->flags &= (~SATA_FLAG_Q_DEP_MASK);
--
1.7.9.5
^ permalink raw reply related [flat|nested] 6+ messages in thread
* [U-Boot] [PATCH v2 4/4] SMDK55250: Enable SATA
2012-11-23 12:08 [U-Boot] [PATCH v2 0/4] Support for SATA on EXYNOS5 Vasanth Ananthan
` (2 preceding siblings ...)
2012-11-23 12:08 ` [U-Boot] [PATCH v2 3/4] Drivers: block: Support for SATA in Exynos5 Vasanth Ananthan
@ 2012-11-23 12:08 ` Vasanth Ananthan
3 siblings, 0 replies; 6+ messages in thread
From: Vasanth Ananthan @ 2012-11-23 12:08 UTC (permalink / raw)
To: u-boot
This patch adds required macros for enabling SATA.
Signed-off-by: Vasanth Ananthan <vasanth.a@samsung.com>
---
include/configs/smdk5250.h | 11 +++++++++++
1 file changed, 11 insertions(+)
diff --git a/include/configs/smdk5250.h b/include/configs/smdk5250.h
index e412da8..123fcc3 100644
--- a/include/configs/smdk5250.h
+++ b/include/configs/smdk5250.h
@@ -97,6 +97,7 @@
#define CONFIG_CMD_EXT2
#define CONFIG_CMD_FAT
#define CONFIG_CMD_NET
+#define CONFIG_CMD_SATA
#define CONFIG_BOOTDELAY 3
#define CONFIG_ZERO_BOOTDELAY_CHECK
@@ -259,4 +260,14 @@
/* Enable devicetree support */
#define CONFIG_OF_LIBFDT
+/* Enable SATA */
+#ifdef CONFIG_CMD_SATA
+ #define CONFIG_DWC_AHSATA
+ #define CONFIG_SYS_SATA_MAX_DEVICE 1
+ #define CONFIG_DWC_AHSATA_PORT_ID 0
+ #define CONFIG_DWC_AHSATA_BASE_ADDR EXYNOS5_SATA_BASE
+ #define CONFIG_LBA48
+ #define CONFIG_LIBATA
+#endif
+
#endif /* __CONFIG_H */
--
1.7.9.5
^ permalink raw reply related [flat|nested] 6+ messages in thread
* [U-Boot] [PATCH v2 3/4] Drivers: block: Support for SATA in Exynos5
2012-11-23 12:08 ` [U-Boot] [PATCH v2 3/4] Drivers: block: Support for SATA in Exynos5 Vasanth Ananthan
@ 2012-11-23 15:41 ` Luka Perkov
0 siblings, 0 replies; 6+ messages in thread
From: Luka Perkov @ 2012-11-23 15:41 UTC (permalink / raw)
To: u-boot
Hi Vasanth,
On Fri, Nov 23, 2012 at 05:38:57PM +0530, Vasanth Ananthan wrote:
> This patch provides support for SATA in Exynos5250
>
> Signed-off-by: Vasanth Ananthan <vasanth.a@samsung.com>
> ---
> drivers/block/dwc_ahsata.c | 394 +++++++++++++++++++++++++++++++++++++++++++-
> 1 file changed, 387 insertions(+), 7 deletions(-)
>
> diff --git a/drivers/block/dwc_ahsata.c b/drivers/block/dwc_ahsata.c
> index c9b71f7..5125134 100644
> --- a/drivers/block/dwc_ahsata.c
> +++ b/drivers/block/dwc_ahsata.c
> @@ -35,6 +35,69 @@
> #include <asm/arch/clock.h>
> #include "dwc_ahsata.h"
>
> +
> +#define bool unsigned char
> +#define false 0
> +#define true 1
Do we really need this ? And if yes we should put it somewhere else.
Bellow are some cosmetic comments...
> +#ifdef SATA_DEBUG
> +#define debug(fmt, args...) printf(fmt, ##args)
> +#else
> +#define debug(fmt, args...)
> +#endif /* MKIMAGE_DEBUG */
> +
> +#define MAX_DATA_BYTES_PER_SG (4 * 1024 * 1024)
> +#define MAX_BYTES_PER_TRANS (AHCI_MAX_SG * MAX_DATA_BYTES_PER_SG)
> +
> +#define writel_with_flush(a, b) do { writel(a, b); readl(b); } while (0)
> +
> +#define EXYNOS5_SATA_PHY_CONTROL (0x10040000 + 0x724)
> +#define S5P_PMU_SATA_PHY_CONTROL_EN 0x1
> +
> +#define SATA_TIME_LIMIT 10000
> +#define SATA_PHY_I2C_SLAVE_ADDRS 0x70
> +
> +#define SATA_RESET 0x4
> +#define RESET_CMN_RST_N (1 << 1)
> +#define LINK_RESET 0xF0000
> +
> +#define SATA_MODE0 0x10
> +
> +#define SATA_CTRL0 0x14
> +#define CTRL0_P0_PHY_CALIBRATED_SEL (1 << 9)
> +#define CTRL0_P0_PHY_CALIBRATED (1 << 8)
> +
> +#define SATA_PHSATA_CTRLM 0xE0
> +#define PHCTRLM_REF_RATE (1 << 1)
> +#define PHCTRLM_HIGH_SPEED (1 << 0)
> +
> +#define SATA_PHSATA_STATM 0xF0
> +#define PHSTATM_PLL_LOCKED (1 << 0)
> +
> +#define SATA_I2C_CON 0x00
> +#define SATA_I2C_STAT 0x04
> +#define SATA_I2C_ADDR 0x08
> +#define SATA_I2C_DS 0x0C
> +#define SATA_I2C_LC 0x10
> +
> +/* I2CCON reg */
> +#define CON_ACKEN (1 << 7)
> +#define CON_CLK512 (1 << 6)
> +#define CON_CLK16 (~CON_CLK512)
> +#define CON_INTEN (1 << 5)
> +#define CON_INTPND (1 << 4)
> +#define CON_TXCLK_PS (0xF)
> +
> +/* I2CSTAT reg */
> +#define STAT_MSTT (0x3 << 6)
> +#define STAT_BSYST (1 << 5)
> +#define STAT_RTEN (1 << 4)
> +#define STAT_LAST (1 << 0)
> +
> +#define LC_FLTR_EN (1 << 2)
> +
> +#define SATA_PHY_CON_RESET 0xF003F
> +
> struct sata_port_regs {
> u32 clb;
> u32 clbu;
> @@ -88,10 +151,244 @@ struct sata_host_regs {
> u32 idr;
> };
>
> -#define MAX_DATA_BYTES_PER_SG (4 * 1024 * 1024)
> -#define MAX_BYTES_PER_TRANS (AHCI_MAX_SG * MAX_DATA_BYTES_PER_SG)
> +void * const phy_ctrl = (void *)EXYNOS5_SATA_PHY_BASE;
> +void * const phy_i2c_base = (void *)EXYNOS5_SATA_PHY_I2C;
>
> -#define writel_with_flush(a, b) do { writel(a, b); readl(b); } while (0)
> +enum {
> + SATA_GENERATION1,
> + SATA_GENERATION2,
> + SATA_GENERATION3,
> +};
> +
> +static bool sata_is_reg(void *base, u32 reg, u32 checkbit, u32 status)
> +{
> + if ((readl(base + reg) & checkbit) == status)
> + return true;
> + else
> + return false;
> +}
> +
> +static bool wait_for_reg_status(void *base, u32 reg, u32 checkbit,
> + u32 status)
> +{
> + u32 time_limit_cnt = 0;
> + while (!sata_is_reg(base, reg, checkbit, status)) {
> + if (time_limit_cnt == SATA_TIME_LIMIT)
> + return false;
> + udelay(1000);
> + time_limit_cnt++;
> + }
> + return true;
> +}
> +
> +static void sata_set_gen(u8 gen)
> +{
> + writel(gen, phy_ctrl + SATA_MODE0);
> +}
> +
> +/* Address :I2C Address */
> +static void sata_i2c_write_addrs(u8 data)
> +{
> + writeb((data & 0xFE), phy_i2c_base + SATA_I2C_DS);
> +}
> +
> +static void sata_i2c_write_data(u8 data)
> +{
> + writeb((data), phy_i2c_base + SATA_I2C_DS);
> +}
> +
> +static void sata_i2c_start(void)
> +{
> + u32 val;
> + val = readl(phy_i2c_base + SATA_I2C_STAT);
> + val |= STAT_BSYST;
> + writel(val, phy_i2c_base + SATA_I2C_STAT);
> +}
> +
> +static void sata_i2c_stop(void)
> +{
> + u32 val;
> + val = readl(phy_i2c_base + SATA_I2C_STAT);
> + val &= ~STAT_BSYST;
> + writel(val, phy_i2c_base + SATA_I2C_STAT);
> +}
> +
> +static bool sata_i2c_get_int_status(void)
> +{
> + if ((readl(phy_i2c_base + SATA_I2C_CON)) & CON_INTPND)
> + return true;
> + else
> + return false;
> +}
> +
> +static bool sata_i2c_is_tx_ack(void)
> +{
> + if ((readl(phy_i2c_base + SATA_I2C_STAT)) & STAT_LAST)
> + return false;
> + else
> + return true;
> +}
> +
> +static bool sata_i2c_is_bus_ready(void)
> +{
> + if ((readl(phy_i2c_base + SATA_I2C_STAT)) & STAT_BSYST)
> + return false;
> + else
> + return true;
> +}
> +
> +static bool sata_i2c_wait_for_busready(u32 time_out)
> +{
> + while (--time_out) {
> + if (sata_i2c_is_bus_ready())
> + return true;
> + udelay(100);
> + }
> + return false;
> +}
> +
> +static bool sata_i2c_wait_for_tx_ack(u32 time_out)
> +{
> + while (--time_out) {
> + if (sata_i2c_get_int_status()) {
> + if (sata_i2c_is_tx_ack())
> + return true;
> + }
> + udelay(100);
> + }
> + return false;
> +}
> +
> +static void sata_i2c_clear_int_status(void)
> +{
> + u32 val;
> + val = readl(phy_i2c_base + SATA_I2C_CON);
> + val &= ~CON_INTPND;
> + writel(val, phy_i2c_base + SATA_I2C_CON);
> +}
> +
> +
Extra new line.
> +static void sata_i2c_set_ack_gen(bool enable)
> +{
> + u32 val;
> + if (enable) {
> + val = (readl(phy_i2c_base + SATA_I2C_CON)) | CON_ACKEN;
> + writel(val, phy_i2c_base + SATA_I2C_CON);
> + } else {
> + val = readl(phy_i2c_base + SATA_I2C_CON);
> + val &= ~CON_ACKEN;
> + writel(val, phy_i2c_base + SATA_I2C_CON);
> + }
> +
Extra new line.
> +}
> +
> +static void sata_i2c_set_master_tx(void)
> +{
> + u32 val;
> + /* Disable I2C */
> + val = readl(phy_i2c_base + SATA_I2C_STAT);
> + val &= ~STAT_RTEN;
> + writel(val, phy_i2c_base + SATA_I2C_STAT);
> + /* Clear Mode */
> + val = readl(phy_i2c_base + SATA_I2C_STAT);
> + val &= ~STAT_MSTT;
> + writel(val, phy_i2c_base + SATA_I2C_STAT);
> + sata_i2c_clear_int_status();
> + /* interrupt disable */
> + val = readl(phy_i2c_base + SATA_I2C_CON);
> + val &= ~CON_INTEN;
> + writel(val, phy_i2c_base + SATA_I2C_CON);
> +
> + /* Master, Send mode */
> + val = readl(phy_i2c_base + SATA_I2C_STAT);
> + val |= STAT_MSTT;
> + writel(val, phy_i2c_base + SATA_I2C_STAT);
> +
> + /* interrupt enable */
> + val = readl(phy_i2c_base + SATA_I2C_CON);
> + val |= CON_INTEN;
> + writel(val, phy_i2c_base + SATA_I2C_CON);
> +
> + /* Enable I2C */
> + val = readl(phy_i2c_base + SATA_I2C_STAT);
> + val |= STAT_RTEN;
> + writel(val, phy_i2c_base + SATA_I2C_STAT);
> +}
> +
> +static void sata_i2c_init(void)
> +{
> + u32 val;
> +
> + val = readl(phy_i2c_base + SATA_I2C_CON);
> + val &= CON_CLK16;
> + writel(val, phy_i2c_base + SATA_I2C_CON);
> +
> + val = readl(phy_i2c_base + SATA_I2C_CON);
> + val &= ~(CON_TXCLK_PS);
> + writel(val, phy_i2c_base + SATA_I2C_CON);
> +
> + val = readl(phy_i2c_base + SATA_I2C_CON);
> + val |= (2 & CON_TXCLK_PS);
> + writel(val, phy_i2c_base + SATA_I2C_CON);
> +
> + val = readl(phy_i2c_base + SATA_I2C_LC);
> + val &= ~(LC_FLTR_EN);
> + writel(val, phy_i2c_base + SATA_I2C_LC);
> +
> + sata_i2c_set_ack_gen(false);
> +}
> +
> +static bool sata_i2c_send(u8 slave_addrs, u8 addrs, u8 ucData)
> +{
> + s32 ret = 0;
> + if (!sata_i2c_wait_for_busready(SATA_TIME_LIMIT))
> + return false;
> +
> + sata_i2c_init();
> + sata_i2c_set_master_tx();
> +
> + writel(SATA_PHY_CON_RESET, phy_ctrl + SATA_RESET);
> + sata_i2c_write_addrs(slave_addrs);
> + sata_i2c_start();
> + if (!sata_i2c_wait_for_tx_ack(SATA_TIME_LIMIT)) {
> + ret = false;
> + goto STOP;
> + }
> + sata_i2c_write_data(addrs);
> + sata_i2c_clear_int_status();
> + if (!sata_i2c_wait_for_tx_ack(SATA_TIME_LIMIT)) {
> + ret = false;
> + goto STOP;
> + }
> + sata_i2c_write_data(ucData);
> + sata_i2c_clear_int_status();
> + if (!sata_i2c_wait_for_tx_ack(SATA_TIME_LIMIT)) {
> + ret = false;
> + goto STOP;
> + }
> + ret = true;
> +
> +STOP:
> + sata_i2c_stop();
> + sata_i2c_clear_int_status();
> + sata_i2c_wait_for_busready(SATA_TIME_LIMIT);
> +
> + return ret;
> +}
> +
> +static bool sata_phy_i2c_init()
> +{
> + /* 0x3A for 40bit I/F */
> + u8 reg_addrs = 0x3A;
> + /* 0x0B for 40bit I/F */
> + u8 default_setting_value = 0x0B;
> +
> + if (!sata_i2c_send(SATA_PHY_I2C_SLAVE_ADDRS, reg_addrs,
> + default_setting_value))
> + return false;
> +
> + return true;
> +}
>
> static int is_ready;
>
> @@ -127,6 +424,58 @@ static int ahci_setup_oobr(struct ahci_probe_ent *probe_ent,
> return 0;
> }
>
> +static int sata_phy_init(int port_num)
> +{
> + int val, ret;
> +
> + writel(S5P_PMU_SATA_PHY_CONTROL_EN, EXYNOS5_SATA_PHY_CONTROL);
> +
> + val = 0;
> + writel(val, phy_ctrl + SATA_RESET);
> + val = readl(phy_ctrl + SATA_RESET);
> + val |= 0x3D;
> + writel(val, phy_ctrl + SATA_RESET);
> +
> + val = readl(phy_ctrl + SATA_RESET);
> + val |= LINK_RESET;
> + writel(val, phy_ctrl + SATA_RESET);
> +
> + val = readl(phy_ctrl + SATA_RESET);
> + val |= RESET_CMN_RST_N;
> + writel(val, phy_ctrl + SATA_RESET);
> +
> + val = readl(phy_ctrl + SATA_PHSATA_CTRLM);
> + val &= ~PHCTRLM_REF_RATE;
> + writel(val, phy_ctrl + SATA_PHSATA_CTRLM);
> +
> + /* High speed enable for Gen3 */
> + val = readl(phy_ctrl + SATA_PHSATA_CTRLM);
> + val |= PHCTRLM_HIGH_SPEED;
> + writel(val, phy_ctrl + SATA_PHSATA_CTRLM);
> +
> + ret = sata_phy_i2c_init();
> +
> + val = readl(phy_ctrl + SATA_CTRL0);
> + val |= CTRL0_P0_PHY_CALIBRATED_SEL|CTRL0_P0_PHY_CALIBRATED;
> + writel(val, phy_ctrl + SATA_CTRL0);
> + sata_set_gen(SATA_GENERATION3);
> +
> + /* release cmu reset */
> + val = readl(phy_ctrl + SATA_RESET);
> + val &= ~RESET_CMN_RST_N;
> + writel(val, phy_ctrl + SATA_RESET);
> +
> + val = readl(phy_ctrl + SATA_RESET);
> + val |= RESET_CMN_RST_N;
> + writel(val, phy_ctrl + SATA_RESET);
> +
> + if (wait_for_reg_status(phy_ctrl, SATA_PHSATA_STATM,
> + PHSTATM_PLL_LOCKED, 1)) {
> + return ret;
> + }
> + return 0;
> +}
> +
> static int ahci_host_init(struct ahci_probe_ent *probe_ent)
> {
> u32 tmp, cap_save, num_ports;
> @@ -134,10 +483,11 @@ static int ahci_host_init(struct ahci_probe_ent *probe_ent)
> struct sata_port_regs *port_mmio = NULL;
> struct sata_host_regs *host_mmio =
> (struct sata_host_regs *)probe_ent->mmio_base;
> - int clk = mxc_get_clock(MXC_SATA_CLK);
> + int clk = get_sata_clock();
>
> cap_save = readl(&(host_mmio->cap));
> cap_save |= SATA_HOST_CAP_SSS;
> + cap_save &= ~(SATA_HOST_CAP_SMPS);
>
> /* global controller reset */
> tmp = readl(&(host_mmio->ghc));
> @@ -159,7 +509,7 @@ static int ahci_host_init(struct ahci_probe_ent *probe_ent)
> ahci_setup_oobr(probe_ent, 0);
>
> writel_with_flush(SATA_HOST_GHC_AE, &(host_mmio->ghc));
> - writel(cap_save, &(host_mmio->cap));
> + writel_with_flush(cap_save, &(host_mmio->cap));
> num_ports = (cap_save & SATA_HOST_CAP_NP_MASK) + 1;
> writel_with_flush((1 << num_ports) - 1,
> &(host_mmio->pi));
> @@ -219,11 +569,37 @@ static int ahci_host_init(struct ahci_probe_ent *probe_ent)
> debug("port reset failed (0x%x)\n", tmp);
> return -1;
> }
> +
> + tmp &= ~SATA_PORT_CMD_FRE;
> + writel_with_flush(tmp, &(port_mmio->cmd));
> +
> + timeout = 1000;
> +
> + while ((readl(&(port_mmio->cmd)) & SATA_PORT_CMD_FR)
> + && --timeout)
> + ;
> +
> + if (timeout <= 0) {
> + debug("port reset failed (0x%x)\n", tmp);
> + return -1;
> + }
> }
>
> + tmp = readl(&(port_mmio->sctl));
> + tmp &= (SATA_PORT_SSTS_DET_MASK);
> + writel_with_flush(tmp, &(port_mmio->sctl));
> +
> /* Spin-up device */
> tmp = readl(&(port_mmio->cmd));
> - writel((tmp | SATA_PORT_CMD_SUD), &(port_mmio->cmd));
> +
> + tmp |= (SATA_PORT_CMD_SUD |
> + SATA_PORT_CMD_HPCP);
> +
> + tmp &= ~(SATA_PORT_CMD_MPSP |
> + SATA_PORT_CMD_CPD |
> + SATA_PORT_CMD_ESP);
> +
> + writel(tmp, &(port_mmio->cmd));
>
> /* Wait for spin-up to finish */
> timeout = 1000;
> @@ -235,6 +611,8 @@ static int ahci_host_init(struct ahci_probe_ent *probe_ent)
> return -1;
> }
>
> + sata_phy_init(i);
> +
> for (j = 0; j < 100; ++j) {
> mdelay(10);
> tmp = readl(&(port_mmio->ssts));
> @@ -273,7 +651,7 @@ static int ahci_host_init(struct ahci_probe_ent *probe_ent)
>
> /* set irq mask (enables interrupts) */
> writel(DEF_PORT_IRQ, &(port_mmio->ie));
> -
> + mdelay(100);
> /* register linkup ports */
> tmp = readl(&(port_mmio->ssts));
> debug("Port %d status: 0x%x\n", i, tmp);
> @@ -941,11 +1319,13 @@ int scan_sata(int dev)
> pdev->blksz = ATA_SECT_SIZE;
> pdev->lun = 0 ;
>
> +#ifdef CONFIG_LBA48
> /* Check if support LBA48 */
> if (ata_id_has_lba48(id)) {
> pdev->lba48 = 1;
> debug("Device support LBA48\n\r");
> }
> +#endif
>
> /* Get the NCQ queue depth from device */
> probe_ent->flags &= (~SATA_FLAG_Q_DEP_MASK);
> --
> 1.7.9.5
Luka
^ permalink raw reply [flat|nested] 6+ messages in thread
end of thread, other threads:[~2012-11-23 15:41 UTC | newest]
Thread overview: 6+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2012-11-23 12:08 [U-Boot] [PATCH v2 0/4] Support for SATA on EXYNOS5 Vasanth Ananthan
2012-11-23 12:08 ` [U-Boot] [PATCH v2 1/4] Exynos5: Add clock support for SATA Vasanth Ananthan
2012-11-23 12:08 ` [U-Boot] [PATCH v2 2/4] Exynos5: Add base addresses " Vasanth Ananthan
2012-11-23 12:08 ` [U-Boot] [PATCH v2 3/4] Drivers: block: Support for SATA in Exynos5 Vasanth Ananthan
2012-11-23 15:41 ` Luka Perkov
2012-11-23 12:08 ` [U-Boot] [PATCH v2 4/4] SMDK55250: Enable SATA Vasanth Ananthan
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox